[英]How to extract character n-grams based on a large text
给定一个大文本文件,我想使用Apache Spark提取字符n-gram(并行完成任务)。
示例输入(2行文本):第1行:( Hello World,它)第2行:(是美好的一天)
输出n-gram:Hel - ell -llo -lo_ - o_W - _Wo - Wor - orl - rld - ld, - d,_ - ,_ i - _it - it_ - t_i - _is - ...等等。 所以我希望返回值是RDD [String],每个字符串包含n-gram。
请注意,新行在输出n-gram中被视为空格。 我把括号中的每一行都清楚了。 另外,要清楚字符串或文本不是RDD中的单个条目。 我使用sc.textFile()方法读取该文件。
您可以使用如下函数:
def n_gram(str:String, n:Int) = (str + " ").sliding(n)
我假设换行时读取了换行符,所以我添加了一个空格来弥补这一点。 另一方面,如果保留换行符,则可以将其定义为:
def n_gram(str:String, n:Int) = str.replace('\n', ' ').sliding(n)
使用你的例子:
println(n_gram("Hello World, it", 3).map(_.replace(' ', '_')).mkString(" - "))
会回来:
Hel - ell - llo - lo_ - o_W - _Wo - Wor - orl - rld - ld, - d,_ - ,_i - _it - it_
主要思想是获取每个分区中的所有行并将它们组合成一个长字符串。 接下来,我们用“_”替换“”并在此字符串上调用滑动以并行创建每个分区的三元组。
注意:由于我们将从每个分区的开头和结尾错过很少的三元组,因此得到的三元组可能不是100%准确。 鉴于每个分区的长度可能是几百万个字符,保证的损失应该可以忽略不计。 这里的主要好处是每个分区可以并行执行。
这是一些玩具数据。 以下所有内容都可以在任何Spark REPL上执行:
scala> val data = sc.parallelize(Seq("Hello World, it","is a nice day"))
data: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[12]
val trigrams = data.mapPartitions(_.toList.mkString(" ").replace(" ","_").sliding(3))
trigrams: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[14]
在这里,我将收集三元组以显示它们的样子(如果您的数据集很大,您可能不想这样做)
scala> val asCollected = trigrams.collect
asCollected: Array[String] = Array(Hel, ell, llo, lo_, o_W, _Wo, Wor, orl, rld, ld,, d,_, ,_i, _it, is_, s_a, _a_, a_n, _ni, nic, ice, ce_, e_d, _da, day)
可能有更短的方法来做到这一点,
假设整个字符串(包括新行)是RDD中的单个条目,从flatMap返回以下内容应该可以得到您想要的结果。
val strings = text.foldLeft(("", List[String]())) {
case ((s, l), c) =>
if (s.length < 2) {
val ns = s + c
(ns, l)
} else if (s.length == 2) {
val ns = s + c
(ns, ns :: l)
} else {
val ns = s.tail + c
(ns, ns :: l)
}
}._2
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.