如何使用Spark查找文本表中的关键字?

时间:2016-06-01 06:26:29

标签: scala apache-spark apache-spark-sql

我是Spark的新手。我在HDFS中有两个表。一个表(表1)是一个标签表,由一些文本组成,可以是一些单词或一个句子。另一个表(表2)有一个文本列。每一行在表1中可以有多个关键字。我的任务是找出表1中表2中文本列的所有匹配关键字,并输出表2中每一行的关键字列表。

问题是我必须迭代表2和表1中的每一行。如果我为表1生成一个大列表,并使用表2的映射函数。我仍然需要使用循环来迭代列表在地图功能。并且驱动程序显示JVM内存限制错误,即使循环不是很大(10万次)。

myTag是表1的标签列表。

row1|Spark  
row2|RDD 

有任何建议要完成这项任务吗?有或没有Spark 非常感谢!

一个例子如下:

表1

row1| Spark is a fast and general engine. RDD supports two types of operations.  
row2| All transformations in Spark are lazy.  
row3| It is for test. I am a sentence.

表2

row1| Spark,RDD  
row2| Spark  

预期结果:

row1| Spark  
row2| RDD  
row3| two words  
row4| I am a sentence

主要编辑:

第一个表实际上可能包含句子,而不仅仅是简单的关键字:

<!DOCTYPE html>
<html>
    <head>
        <style type="text/css">
            p {color;blue;}
        </style>
    </head>
    <body>
        <p>This text is blue</p>
    </body>
</html>

2 个答案:

答案 0 :(得分:1)

在这里,考虑您提供的数据样本:

val table1: Seq[(String, String)] = Seq(("row1", "Spark"), ("row2", "RDD"), ("row3", "Hashmap"))
val table2: Seq[String] = Seq("row1##Spark is a fast and general engine. RDD supports two types of operations.", "row2##All transformations in Spark are lazy.")
val rdd1: RDD[(String, String)] = sc.parallelize(table1)
val rdd2: RDD[(String, String)] = sc.parallelize(table2).map(_.split("##").toList).map(l => (l.head, l.tail(0))).cache

我们将构建第二个数据表的倒排索引,我们将加入第一个表:

val df1: DataFrame = rdd1.toDF("key", "value")
val df2: DataFrame = rdd2.toDF("key", "text")
val df3: DataFrame = rdd2.flatMap { case (row, text) => text.trim.split( """[^\p{IsAlphabetic}]+""")
  .map(word => (word, row))
}.groupByKey.mapValues(_.toSet.toSeq).toDF("word", "index")

import org.apache.spark.sql.functions.explode

val results: RDD[(String, String)] = df3.join(df1, df1("value") === df3("word")).drop("key").drop("value").withColumn("index", explode($"index")).rdd.map {
  case r: Row => (r.getAs[String]("index"), r.getAs[String]("word"))
}.groupByKey.mapValues(i => i.toList.mkString(","))

results.take(2).foreach(println)
// (row1,Spark,RDD)
// (row2,Spark)

主要编辑:

如评论中所述:问题的规格发生了变化。关键字不再是简单的关键字,它们可能是句子。在这种情况下,这种方法不会起作用,这是一种不同的问题。一种方法是使用Locality-sensitive hashing (LSH)算法进行最近邻搜索。

此算法的实现可用here

遗憾的是,算法及其实现在SO上讨论的时间太长。

答案 1 :(得分:0)

从我的问题陈述中可以收集到的是,您尝试使用表1中的关键字标记表2中的数据。为此,不要将Table1作为列表加载然后执行表2中每行的每个关键字模式匹配,执行以下操作:

  1. 将Table1加载为hashSet。
  2. 遍历Table2,对于该短语中的每个单词,在上面的hashset中进行搜索。我假设与每个关键字的模式匹配相比,您必须从此处搜索的单词数量较少。请记住,现在搜索是O(1)操作,而模式匹配则不是。
  3. 此外,在此过程中,您还可以过滤“is,are,when,if”等字样,因为它们永远不会用于标记。这样就减少了你需要在hashSet中找到的单词。
  4. hashSet可以加载到内存中(我认为10K关键字不应该超过几MB)。可以通过广播变量在执行程序之间共享此变量。