mmseg4j 用 Chih-Hao Tsai 的 MMSeg 算法实现的中文分词器,并实现 lucene 的 analyzer 和 solr 的TokenizerFactory 以方便在Lucene和Solr中使用。
MMSeg 算法有两种分词方法:Simple和Complex,都是基于正向最大匹配。Complex 加了四个规则过虑。官方说:词语的正确识别率达到了 98.41%。mmseg4j 已经实现了这两种分词算法。
项目地址:
mmseg4j:https://github.com/chenlb/mmseg4j-from-googlecode
mmseg4j-core:https://github.com/chenlb/mmseg4j-core
mmseg4j-solr:https://github.com/chenlb/mmseg4j-solr
mmseg4j有几个analyzer:SimpleAnalyzer、ComplexAnalyzer、MaxWordAnalyzer、MMSegAnalyzer。前面三个都是继承 MMSegAnalyzer,MMSegAnalyzer 默认使用 max-word 方式分词。这些 analyzer 都有无参数的构造函数,还有一个带词库目录为参数的构造函数。
mmseg4j 的词库是使用utf-8 格式的,由于utf-8文件有带与不带 BOM 之分,建议词库第一行为空行或为无 BOM 格式的 utf-8 文件。
可以根据需要替换的词库文件:
data/chars.dic 是单字与语料中的频率,一般不用改动,mmseg4j 1.5版本后已经加到mmseg4j的jar里了,我们不需要关心它,当然你在词库目录放这个文件可以覆盖它。
data/units.dic 是单字的单位,默认读jar包里的,你也可以自定义覆盖它,这功能是试行,如果不喜欢它,可以空的units.dic文件(放到你的词库目录下)覆盖它。
词库文件:
data/words.dic 是词库文件,一行一词,当然你也可以使用自己的,1.5版本使用 sogou 词库,1.0的版本是用 rmmseg 带的词库。 一般我们使用这个作为系统自带词库。分词效果当然还与词库有关,sogou 的词库是统计得出,有些高频的单字组合也成了词,如“我们的”。如果还要提高 mmseg4j 的分词效果,还要在整理下词库。
data/wordsxxx.dic 1.6版支持多个词库文件,data 目录(或你定义的目录)下读到"words"前缀且".dic"为后缀的文件。如:data/words-my.dic。 一般我们在这里里面,把这个当成我们自身特色的词库。
停止词
mmseg4j没有加任何stopword,如果需要stopword,需要用户自己实现。
maven依赖:
<properties> <lucene.version>5.2.1</lucene.version> </properties> <dependencies> <dependency> <groupId> org.apache.lucene</groupId> <artifactId> lucene-core</artifactId> <version> ${lucene.version}</version> </dependency> <dependency> <groupId> org.apache.lucene</groupId> <artifactId> lucene-analyzers-common</artifactId> <version> ${lucene.version}</version> </dependency> <dependency> <groupId> org.apache.lucene</groupId> <artifactId> lucene-queryparser</artifactId> <version> ${lucene.version}</version> </dependency> <dependency> <groupId> org.apache.lucene</groupId> <artifactId> lucene-highlighter</artifactId> <version> ${lucene.version}</version> </dependency> <dependency> <groupId>com.chenlb.mmseg4j</groupId> <artifactId>mmseg4j-core</artifactId> <version>1.10.0</version> </dependency> <!-- 如下可以编译最新的mmseg4j-analysis替换,不然加载报错 --> <dependency> <groupId>com.chenlb.mmseg4j</groupId> <artifactId>mmseg4j-solr</artifactId> <version>2.3.0</version> <exclusions> <exclusion> <groupId>org.apache.solr</groupId> <artifactId>solr-core</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
测试实例:
package cn.slimsmart.lucene.mmseg4j.demo; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.TextField; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.IndexWriterConfig.OpenMode; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TopDocs; import org.apache.lucene.store.Directory; import org.apache.lucene.store.RAMDirectory; import com.chenlb.mmseg4j.analysis.ComplexAnalyzer; public class Test { static Analyzer analyzer = null; static Directory directory = null; static String text = "CSDN.NET - 全球最大中文IT社区,为IT专业技术人员提供最全面的信息传播和服务平台"; public static void main(String[] args) throws Exception { analyzer = new ComplexAnalyzer(); directory = new RAMDirectory(); write(); search(); } /** * 简单分词 * * @throws Exception */ public static void write() throws Exception { IndexWriterConfig iwConfig = new IndexWriterConfig(analyzer); iwConfig.setOpenMode(OpenMode.CREATE_OR_APPEND); IndexWriter iwriter = new IndexWriter(directory, iwConfig); Document doc = new Document(); doc.add(new TextField("text", text, Field.Store.YES)); iwriter.addDocument(doc); iwriter.commit(); iwriter.close(); } public static void search() throws Exception { IndexReader ireader = DirectoryReader.open(directory); IndexSearcher searcher = new IndexSearcher(ireader); QueryParser qp = new QueryParser("text", analyzer); Query q = qp.parse("全球最大"); System.out.println(q); TopDocs tds = searcher.search(q, 10); System.out.println("======size:" + tds.totalHits + "========"); for (ScoreDoc sd : tds.scoreDocs) { System.out.println(sd.score); System.out.println(searcher.doc(sd.doc).get("text")); } } }
参考文章:
1.官方博客
2.中文分词 mmseg4j