Spark-Ansj中文文本分词

ansj还是很好用的:快、相对于准确率高、功能多。

https://github.com/NLPchina/ansj_seg

直接上代码:

import java.io.InputStream
import java.util

import org.ansj.domain.Result
import org.ansj.recognition.impl.StopRecognition
import org.ansj.splitWord.analysis.ToAnalysis
import org.ansj.util.MyStaticValue
import org.apache.spark.{SparkConf, SparkContext}
import org.nlpcn.commons.lang.tire.domain.{Forest, Value}
import org.nlpcn.commons.lang.tire.library.Library

class ChineseSegmentation extends Serializable {

  @transient private val sparkConf: SparkConf = new SparkConf().setAppName("chinese segment")
  @transient private val sparkContext: SparkContext = SparkContext.getOrCreate(sparkConf)

  private val stopLibRecog = new StopLibraryRecognit
  private val stopLib: util.ArrayList[String] = stopLibRecog.stopLibraryFromHDFS(sparkContext)
  private val selfStopRecognition: StopRecognition = stopLibRecog.stopRecognitionFilter(stopLib)

  private val dicUserLibrary = new DicUserLibrar
  @transient private val aListDicLibrary: util.ArrayList[Value] = dicUserLibrary.getUserLibraryList(sparkContext)
  @transient private val dirLibraryForest: Forest = Library.makeForest(aListDicLibrary)

  /**中文分词和模式识别*/
  def cNSeg(comment : String) : String = {

    val result: Result = ToAnalysis.parse(comment,dirLibraryForest).recognition(selfStopRecognition)
    result.toStringWithOutNature(" ")
  }
}

/**停用词典识别:
  * 格式: 词语  停用词类型[可以为空]  使用制表符Tab进行分割
  * 如:
  * #
  * v nature
  * .*了 regex
  *
  * */

class StopLibraryRecognit extends Serializable {

  def stopRecognitionFilter(arrayList: util.ArrayList[String]): StopRecognition ={

    MyStaticValue.isQuantifierRecognition = true //数字和量词合并

    val stopRecognition = new StopRecognition

    //识别评论中的介词(p)、叹词(e)、连词(c)、代词(r)、助词(u)、字符串(x)、拟声词(o)
    stopRecognition.insertStopNatures("p", "e", "c", "r", "u", "x", "o")

    stopRecognition.insertStopNatures("w")  //剔除标点符号

    //剔除以中文数字开头的,以一个字或者两个字为删除单位,超过三个的都不删除
    stopRecognition.insertStopRegexes("^一.{0,2}","^二.{0,2}","^三.{0,2}","^四.{0,2}","^五.{0,2}",
      "^六.{0,2}","^七.{0,2}","^八.{0,2}","^九.{0,2}","^十.{0,2}")

    stopRecognition.insertStopNatures("null") //剔除空

    stopRecognition.insertStopRegexes(".{0,1}")  //剔除只有一个汉字的

    stopRecognition.insertStopRegexes("^[a-zA-Z]{1,}")  //把分词只为英文字母的剔除掉

    stopRecognition.insertStopWords(arrayList)  //添加停用词

    stopRecognition.insertStopRegexes("^[0-9]+") //把分词只为数字的剔除

    stopRecognition.insertStopRegexes("[^a-zA-Z0-9\u4e00-\\u9fa5]+")  //把不是汉字、英文、数字的剔除

    stopRecognition
  }


  def stopLibraryFromHDFS(sparkContext: SparkContext): util.ArrayList[String] ={
    /** 获取stop.dic文件中的数据 方法二:
      * 在集群上运行的话,需要把stop的数据放在hdfs上,这样集群中所有的节点都能访问到停用词典的数据 */
    val stopLib: Array[String] = sparkContext.textFile("hdfs://zysdmaster000:8020/data/library/stop.dic").collect()
    val arrayList: util.ArrayList[String] = new util.ArrayList[String]()
    for (i<- 0 until stopLib.length)arrayList.add(stopLib(i))

    arrayList

  }

}



/**用户自定义词典:
  * 格式:词语 词性  词频
  * 词语、词性和词频用制表符分开(Tab)
  *
  * */
class DicUserLibrar extends Serializable {

  def getUserLibraryList(sparkContext: SparkContext): util.ArrayList[Value] = {
    /** 获取userLibrary.dic文件中的数据 方法二:
      * 在集群上运行的话,需要把userLibrary的数据放在hdfs上,这样集群中所有的节点都能访问到user library的数据 */
    val va: Array[String] = sparkContext.textFile("hdfs://zysdmaster000:8020/data/library/userLibrary.dic").collect()
    val arrayList: util.ArrayList[Value] = new util.ArrayList[Value]()
    for (i <- 0 until va.length)arrayList.add(new Value(va(i)))
    arrayList
  }

  def getUserLibraryForest: Forest = {

    /** 获取userLibrary.dic文件中的数据,此方法不适用在集群上运行 方法一:
      * 如果在本地运行的话,可以把userLibrary.dic文件方法src目录(sources格式)下,使用映射方法获取,
      * “/library/userLibrary.dic”和“/userLibrary.dic”两种方式均能获取userLibrary.dic中的数据 */
    val stream: InputStream = DicUserLibrar.this.getClass.getResourceAsStream("/library/userLibrary.dic")
    println(stream)
    /** userLibrary.dic文件放在src目录(sources格式)下 */
    val forestLibrary: Forest = Library.makeForest(DicUserLibrar.this.getClass.getResourceAsStream("/userLibrary.dic"))
    forestLibrary
  }
}

类ChineseSegmentation的使用:

  def contentSegment(dataFrame: DataFrame): DataFrame ={

    val chineseSegmentation = new ChineseSegmentation

    dataFrame.map{line =>
      val str = chineseSegmentation.cNSeg(line(1).toString)
      (line(0).toString,str)
    }.toDF("category","segment").filter("segment != ''").select("category", "segment").map { h =>
      contentRecord(h(0).toString, h(1).toString)
    }.toDF()
  }

使用RDD和DataFrame的算子操作时,不要嵌套sparkContext等操作

你可能感兴趣的:(spark)