Lucene 默认情况下(即使用 StandardAnalyzer 的时候)对中文进行单字分词,即为每个字建立索引。
文档中有 JE 和 IK 分词器的介绍和实例。
1. 分词方法
l 单字分词
l 二分法:把一段文字的每两个相邻的字算作一个词。如“我爱你中国”,将被分为“我爱”、“爱你”、“你中”、“中国”
l 词典法:建立词典文件,词典与文字段落匹配,词典和匹配算法是关键
l 语义法:
2. Lucene 分词器
2.1 二分法分词器
在 Lucene 软件包的 contrib/analyzers 目录下有一个名为 lucene-analyzers-2.1.0.jar 的文件,其中含有二分法分词器 CJKAnalyzer ,只需将此文件加入编译路径即可使用。
注意:要把 C:/lucene/contrib/analyzers/lucene-analyzers-2.1.0.jar 加入到 CLASSPATH 中
实例一:对字符串进行分词
// UseCJK.java
import org.apache.lucene.analysis.cjk.CJKAnalyzer;
import org.apache.lucene.analysis.cjk.CJKTokenizer;
import java.io.StringReader;
public class UseCJK{
public static void main(String args[]) throws java.io.IOException{
String s = " 我爱伟大的祖国,我爱壮丽的中华 ";
StringReader sr = new StringReader(s);
CJKTokenizer cjk = new CJKTokenizer(sr); // 参数
org.apache.lucene.analysis.Token t = null;
while((t=cjk.next())!=null){
System.out.print(t.termText()+"|");
}
}
}
//C:/java>java UseCJK
// 我爱 | 爱伟 | 伟大 | 大的 | 的祖 | 祖国 | 我爱 | 爱壮 | 壮丽 | 丽的 | 的中 | 中华 ||
示例二:用 CJK 分词器对目录下文件建索引
//CJKDirIndexer.java 对目录下文件建索引,使用 CJKIndexer 二分法分词器
import java.io.*;
import tool.FileText; // 自定义的类,获取文件内容
import tool.FileList; // 列目录类
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexWriter;
//import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.analysis.cjk.CJKAnalyzer; // 引入的分词器不同
public class CJKDirIndexer{
public static void main(String args[]) throws java.io.IOException{
String indexPath = "index";
IndexWriter indexWriter = new IndexWriter(indexPath,new CJKAnalyzer()); // 使用的分词器不同
String strFile[] = FileList.getFiles("c:/java/doc");
for(int i=0;i<strFile.length;i++)
{
Document doc = new Document();
File f = new File(strFile[i]);
String name = f.getName();
Field field1 = new Field("name",name,Field.Store.YES,Field.Index.TOKENIZED);
doc.add(field1);
String content = FileText.getText(f);
Field field2 = new Field("content",content,Field.Store.YES,Field.Index.TOKENIZED);
doc.add(field2);
String path = f.getPath();
Field field3 = new Field("path",path,Field.Store.YES,Field.Index.NO);
doc.add(field3);
indexWriter.addDocument(doc);
}
indexWriter.close();
System.out.println("CJK Index Created");
}
}
实例三:检索,差别不大
//CJKSearcher.java
import org.apache.lucene.analysis.cjk.CJKAnalyzer; // 引入 CJK 分词器
import org.apache.lucene.index.*;
import org.apache.lucene.search.*;
import org.apache.lucene.document.*;
public class CJKSearcher
{
public static void main(String[] args) throws java.io.IOException
{
String indexPath = "index";
String searchField = "content";
String searchPhrase = " 大禹 "; // 关键词,双字 哦
StringBuffer sb = new StringBuffer("");
//IndexSearcher
IndexSearcher searcher = new IndexSearcher(indexPath);
//Term & Query
Term t = new Term(searchField, searchPhrase);
Query q = new TermQuery(t);
//Hits
Hits hs = searcher.search(q);
int num = hs.length();
//view details
for(int i=0;i<num;i++)
{
//get document
Document doc = hs.doc(i);
//field name
Field fname = doc.getField("name");
sb.append("name:" + "/n");
sb.append(fname.stringValue() + "/n");
//field content
Field fcontent = doc.getField("content");
sb.append("content:" + "/n");
sb.append(fcontent.stringValue().substring(0,50) + "/n");
sb.append("------------------- " + "/n");
}
searcher.close();
System.out.print(sb);
}
}
2.2 Lucene 自带的中文分词器
中文分词器 ChineseAnalyer ,也在 contrib/analyzers 目录下 lucene-analyzers-2.1.0.jar 文件中
注意: ChineseAnalyer 是单字分词
示例: UseCN.java 字符串分词
//UseCN.java
import org.apache.lucene.analysis.cn.ChineseAnalyzer;
import org.apache.lucene.analysis.cn.ChineseTokenizer;
import java.io.StringReader;
public class UseCN
{
public static void main(String[] args) throws java.io.IOException
{
String s = " 我爱我伟大的老爸老妈,我爱我壮丽的中华! ";
StringReader sr = new StringReader(s);
ChineseTokenizer cn = new ChineseTokenizer(sr);
org.apache.lucene.analysis.Token t = null;
while( (t=cn.next()) !=null )
{
System.out.print(t.termText()+"|");
}
}
}
//C:/java>java UseCN
// 我 | 爱 | 我 | 伟 | 大 | 的 | 老 | 爸 | 老 | 妈 | 我 | 爱 | 我 | 壮 | 丽 | 的 | 中 | 华 |
2.3 NGram 分词器
NGram 分词器也在 contrib/analyzers 目录下 lucene-analyzers-2.1.0.jar 文件中
同时进行单字分词和二分法分词
//UseCN.java
//import org.apache.lucene.analysis.ngram.NGramAnalyzer;
import org.apache.lucene.analysis.ngram.NGramTokenizer;
import java.io.StringReader;
public class UseNGram
{
public static void main(String[] args) throws java.io.IOException
{
String s = " 我爱我伟大的老爸老妈,我爱我壮丽的中华! ";
StringReader sr = new StringReader(s);
NGramTokenizer cn = new NGramTokenizer(sr);
org.apache.lucene.analysis.Token t = null;
while( (t=cn.next()) !=null )
{
System.out.print(t.termText()+"|");
}
}
}
//C:/java>java UseNGram
// 我 | 爱 | 我 | 伟 | 大 | 的 | 老 | 爸 | 老 | 妈 | , | 我 | 爱 | 我 | 壮 | 丽 | 的 | 中 | 华 | ! | 我爱 | 爱我 | 我伟 | 伟大 |
// 大的 | 的老 | 老爸 | 爸老 | 老妈 | 妈, | ,我 | 我爱 | 爱我 | 我壮 | 壮丽 | 丽的 | 的中 | 中华 | 华! |
2.4 JE 分词器
从 http://www.jesoft.cn/ 下载
需要将 je-analysis-1.5.1.jar 放到编译路径中 (classpath)
由中科院提供的中文极易分词器。比较完善的中文分词器,使用简单,维护容易
引入分词器:
import jeasy.analysis.MMAnalyzer;
功能:去除停用词
l 创建对象:
MMAnalyzer mm = new MMAnalyzer();
也可以传递一个参数,设定正向匹配的最大长度
MMAnalyzer mm = new MMAnalyzer(4);
最大匹配长度为 4
l MMAnalyzer.addDictionary(Reader reader);
增加一个新词典,采用每行一个词的读取方式(注意:多线程状态下分词效果不可预料)
l MMAnalyzer.addWord(String newWord);
增加一个新词
l MMAnalyzer.clear()
删除词库中的全部词语
l MMAnalyzer.contains(String word);
判断词库中是否包含该词
l MMAnalyzer.removeWord(String word)
从词库中移除该词
l MMAnalyzer.size()
获得当前词库中包含词语总数。
//UseJE.java
import jeasy.analysis.MMAnalyzer;
public class UseJE
{
public static void main(String[] args) throws java.io.IOException
{
String s = " 我爱我伟大的老爸老妈,我爱我壮丽的中华! ";
MMAnalyzer mm = new MMAnalyzer();
System.out.print(mm.segment(s,"|"));
}
}
//C:/java>java UseJE
// 我 | 爱我 | 伟大 | 老爸 | 老妈 | 我 | 爱我 | 壮丽 | 中华 |
2.5 IK 分词器
IK 分词器,又称 Lucene 中文分词公用组件。
实现了以词典分词为基础的正反向全切分算法,将 IKAnalyzer.jar 放到编译路径即可。
该分词器包括两个分析器:
l MIK_CAnalyzer 使用最大全切分算法,
l IK_CAnalyzer 使用细粒度全切分算法。
引入分词器:
l import org.mira.lucene.analysis.MIK_CAnalyzer
l import org.mira.lucene.analysis.IK_CAnalyzer;
IKAnalyzer 是一个开源的,基于 java 语言开发的轻量级的中文分词工具包。从 2006 年 12 月推出 1.0 版开始, IKAnalyzer 已经推出 了 3 个大版本。最初,它是以开源项目 Luence 为应用主体的,结合词典分词和文法分析算法的中文分词组件。新版本的 IKAnalyzer3.0 则发展为 面向 Java 的公用分词组件,独立于 Lucene 项目,同时提供了对 Lucene 的默认优化实现。
IKAnalyzer3.0 特性 :
采用了特有的“正向迭代最细粒度切分算法“,具有 60 万字 / 秒的高速处理能力。
采用了多子处理器分析模式,支持:英文字母( IP 地址、 Email 、 URL )、数字(日期,常用中文数量词,罗马数字,科学计数法),中文词汇(姓名、地名处理)等分词处理。
优化的词典存储,更小的内存占用。支持用户词典扩展定义
针对 Lucene 全文检索优化的查询分析器 IKQueryParser( 作者吐血推荐 ) ;采用歧义分析算法优化查询关键字的搜索排列组合,能极大的提高 Lucene 检索的命中率。注意: IKQueryParser在IK3.0之后版本中出现
// UseIK.java IK 分词器
import org.mira.lucene.analysis.IK_CAnalyzer; // 引入 IK 分词器
import org.apache.lucene.analysis.TokenStream;
import java.io.*;
public class UseIK{
public static void main(String args[]) throws java.io.IOException{
String s = " 我爱伟大的祖国,我爱壮丽的中华 ";
StringReader sr = new StringReader(s);
IK_CAnalyzer ik = new IK_CAnalyzer(); // 创建分词器
TokenStream ts = ik.tokenStream("*",sr);
org.apache.lucene.analysis.Token t = null;
while((t=ts.next())!=null){
System.out.print(t.termText()+"|");
}
}
}
//C:/java>java UseIK
// 我 | 爱伟 | 伟大 | 大的 | 祖国 | 我 | 爱壮丽 | 壮丽 | 中华 |
经验证, IK比MIK的切分粒度要小
C:/java>java UseIK
我|爱我|我|伟大|大的|老爸|老妈|我|爱我|我|壮丽|中华民族|中华|民族|
C:/java>java UseMI
我|爱我|伟大|大的|老爸|老妈|我|爱我|壮丽|中华民族|
2.6 其它分词器
中科院做了个分词器,是 dll 组件形式,想要在 java 中使用需要 JNI.
现在的主流分词器都是大量统计的结果。