python - sources - spark streaming twitter
Coincidencia eficiente de cadenas en Apache Spark (1)
Usando una herramienta de OCR, extraje textos de capturas de pantalla (aproximadamente 1-5 oraciones cada uno). Sin embargo, al verificar manualmente el texto extraído, noté varios errores que ocurren de vez en cuando.
Dado el texto "¡Hola, π! ¡Me gusta mucho Spark β€οΈ!", Me di cuenta de que:
1) Las letras como "I", "!" Y "l" se reemplazan por "|".
2) Los emojis no se extraen correctamente y se reemplazan por otros personajes o se dejan fuera.
3) Los espacios en blanco se eliminan de vez en cuando.
Como resultado, podría terminar con una cadena como esta: "¡Hola, 7l | real | y me gusta Spark!"
Como estoy tratando de hacer coincidir estas cadenas con un conjunto de datos que incluye el texto correcto (en este caso, "¡Hola, π! ¡Realmente me gusta Spark β€οΈ!"), Estoy buscando una manera eficiente de hacer coincidir la cadena en Spark.
¿Alguien puede sugerir un algoritmo eficiente para Spark que me permita comparar los textos extraídos (~ 100.000) con mi conjunto de datos (~ 100 millones)?
No usaría Spark en primer lugar, pero si realmente está comprometido con la pila en particular, puede combinar un montón de transformadores ml para obtener las mejores combinaciones.
Necesitarás
Tokenizer
(o
split
):
import org.apache.spark.ml.feature.RegexTokenizer
val tokenizer = new RegexTokenizer().setPattern("").setInputCol("text").setMinTokenLength(1).setOutputCol("tokens")
NGram
(por ejemplo, 3 gramos)
import org.apache.spark.ml.feature.NGram
val ngram = new NGram().setN(3).setInputCol("tokens").setOutputCol("ngrams")
Vectorizer
(por ejemplo,
CountVectorizer
o
HashingTF
):
import org.apache.spark.ml.feature.HashingTF
val vectorizer = new HashingTF().setInputCol("ngrams").setOutputCol("vectors")
y
LSH
:
import org.apache.spark.ml.feature.{MinHashLSH, MinHashLSHModel}
// Increase numHashTables in practice.
val lsh = new MinHashLSH().setInputCol("vectors").setOutputCol("lsh")
Combinar con
Pipeline
import org.apache.spark.ml.Pipeline
val pipeline = new Pipeline().setStages(Array(tokenizer, ngram, vectorizer, lsh))
Ajuste en datos de ejemplo:
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)
Transforma ambos:
val dbHashed = model.transform(db)
val queryHashed = model.transform(query)
y únete
model.stages.last.asInstanceOf[MinHashLSHModel]
.approxSimilarityJoin(dbHashed, queryHashed, 0.75).show
+--------------------+--------------------+------------------+
| datasetA| datasetB| distCol|
+--------------------+--------------------+------------------+
|[Hello there π! ...|[Hello there 7l |...|0.5106382978723405|
+--------------------+--------------------+------------------+
El mismo enfoque se puede utilizar en 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|
# +--------------------+--------------------+------------------+
Relacionado
- Optimice el trabajo de Spark que tiene que calcular cada similitud de entrada y generar N elementos similares para cada uno