Apache Spark中的高效字符串匹配

33
使用OCR工具从截图中提取了文本(每个文本大约1-5句话)。然而,手动验证提取的文本时,我注意到有时会出现几个错误。
例如给定文本“Hello there ! I really like Spark ❤️!”,我发现:
1)字母“I”、“!”和“l”被替换为“|”。
2)表情符号未正确提取,被替换为其他字符或被省略。
3)有时会去掉空格。
因此,可能会得到这样一个字符串:“Hello there 7l | real|y like Spark!”
由于我正在尝试将这些字符串与包含正确文本的数据集进行匹配(在这种情况下是“Hello there! I really like Spark ❤️!”),我正在寻找一种有效的方法来在Spark中比较字符串。
是否有人可以为Spark建议一种有效的算法,使我能够将提取的文本(约100,000个)与数据集(约1亿个)进行比较?

9
这似乎不是一个Spark的问题,而是一个OCR问题,正如你在(2)中所说,一些字符没有被正确提取。因此,任何匹配都很明显会失败。建议重新撰写问题,展示你的屏幕截图、OCR软件和配置的示例,以改善OCR匹配。 - danny
1个回答

41

我不会首选使用Spark,但如果您真的致力于特定的技术栈,您可以结合一堆机器学习转换器来获得最佳匹配。您需要Tokenizer(或split):

import org.apache.spark.ml.feature.RegexTokenizer

val tokenizer = new RegexTokenizer().setPattern("").setInputCol("text").setMinTokenLength(1).setOutputCol("tokens")

NGram(例如3-gram)

import org.apache.spark.ml.feature.NGram

val ngram = new NGram().setN(3).setInputCol("tokens").setOutputCol("ngrams")

Vectorizer(例如CountVectorizerHashingTF):

import org.apache.spark.ml.feature.HashingTF

val vectorizer = new HashingTF().setInputCol("ngrams").setOutputCol("vectors")

以及 LSH:

import org.apache.spark.ml.feature.{MinHashLSH, MinHashLSHModel}

// Increase numHashTables in practice.
val lsh = new MinHashLSH().setInputCol("vectors").setOutputCol("lsh")

Pipeline结合使用。

import org.apache.spark.ml.Pipeline

val pipeline = new Pipeline().setStages(Array(tokenizer, ngram, vectorizer, lsh))

适合示例数据:

val query = Seq("Hello there 7l | real|y like Spark!").toDF("text")
val db = Seq(
  "Hello there ! I really like Spark ❤️!", 
  "Can anyone suggest an efficient algorithm"
).toDF("text")

val model = pipeline.fit(db)

转换两者:

val dbHashed = model.transform(db)
val queryHashed = model.transform(query)

并加入

model.stages.last.asInstanceOf[MinHashLSHModel]
  .approxSimilarityJoin(dbHashed, queryHashed, 0.75).show
+--------------------+--------------------+------------------+                  
|            datasetA|            datasetB|           distCol|
+--------------------+--------------------+------------------+
|[Hello there ! ...|[Hello there 7l |...|0.5106382978723405|
+--------------------+--------------------+------------------+

相同的方法可以在Pyspark中使用

from pyspark.ml import Pipeline
from pyspark.ml.feature import RegexTokenizer, NGram, HashingTF, MinHashLSH

query = spark.createDataFrame(
    ["Hello there 7l | real|y like Spark!"], "string"
).toDF("text")

db = spark.createDataFrame([
    "Hello there ! I really like Spark ❤️!", 
    "Can anyone suggest an efficient algorithm"
], "string").toDF("text")


model = Pipeline(stages=[
    RegexTokenizer(
        pattern="", inputCol="text", outputCol="tokens", minTokenLength=1
    ),
    NGram(n=3, inputCol="tokens", outputCol="ngrams"),
    HashingTF(inputCol="ngrams", outputCol="vectors"),
    MinHashLSH(inputCol="vectors", outputCol="lsh")
]).fit(db)

db_hashed = model.transform(db)
query_hashed = model.transform(query)

model.stages[-1].approxSimilarityJoin(db_hashed, query_hashed, 0.75).show()
# +--------------------+--------------------+------------------+
# |            datasetA|            datasetB|           distCol|
# +--------------------+--------------------+------------------+
# |[Hello there ! ...|[Hello there 7l |...|0.5106382978723405|
# +--------------------+--------------------+------------------+

相关


2
这个有多快?我有两个数据集,一个有1000万行,另一个有7000万行。我需要在它们中比较字符串。需要多长时间?并且如同这个回答中提到的,如果不用Spark,你会怎么做? - Ravi Ranjan
@RaviRanjan 快速相对于什么? - Alper t. Turker
3
我正在计算一张有1000万到7000万行的表格之间的莱文斯坦距离。这需要很长时间。我有两个问题:上述算法有多快?如果不使用Spark会怎么做? - Ravi Ranjan
这对于我们在PySpark中处理的数据大小仍然很慢。你知道是否有更快的方法吗? - stormfield
那么ngram的大小会产生影响。如何决定其值?同时,倒序编写的文本不会被考虑在内吗? - thebluephantom
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接