分词Analyzer(词法分析器)
分词器是Lucene中非常重要的一个知识点,如果你面试时说你用过Lucene面试官一定会问你用的什么分词器。
分词,也称词法分析器(或者叫语言分析器),就是指索引中的内容按什么样的方式来建立,这在全文检索中非常关键,是按英文单词建立索引,还是按中文词意建立索引;这些需要由Analyzer来指定。
对于中文,需要采用字典分词,也叫词库分词;把中文件的词全部放置到一个词库中,按某种算法来维护词库内容;如果匹配到就切分出来成为词语。通常词库分词被认为是最理想的中文分词算法。如:“我们是中国人”,效果为:“我们”、“中国人”。(可以使用SmartChineseAnalyzer,“极易分词” MMAnalyzer ,或者是“庖丁分词”分词器、IKAnalyzer。推荐使用IKAnalyzer )
在这里我们推荐IKAnalyzer。使用时需导入IKAnalyzer.jar,并且拷贝IKAnalyzer.cfg.xml,ext_stopword.dic文件,分词器测试代码如下:
//创建索引的数据 现在写死,以后根据实际应用场景
private String en = "oh my lady gaga"; // oh my god
private String cn = "三大不及掩耳盗铃儿响叮当仁不让";
private String str = "FullText Search Lucene框架的学习tmd吃鸡";
/**
* 把特定字符串按特定的分词器来分词
* @param analyzer
* @param str
* @throws Exception
*/
public void testAnalyzer(Analyzer analyzer,String str) throws Exception {
TokenStream tokenStream = analyzer.tokenStream("content", new StringReader(str));
// 在读取词元流后,需要先重置/重加载一次
tokenStream.reset();
while(tokenStream.incrementToken()){
System.out.println(tokenStream);
}
}
//标准分词:不支持中文
@Test
public void testStandardAnalyzer() throws Exception {
testAnalyzer(new StandardAnalyzer(), cn);
}
//简单分词:不支持中文
@Test
public void testSimpleAnalyzer() throws Exception {
testAnalyzer(new SimpleAnalyzer(), cn);
}
//二分分词:两个字是一个词
@Test
public void testCJKAnalyzer() throws Exception {
testAnalyzer(new CJKAnalyzer(), cn);
}
//词典分词:从词典中查找
@Test
public void testSmartChineseAnalyzer() throws Exception {
testAnalyzer(new SmartChineseAnalyzer(), cn);
}
//IK分词:从词典中查找
// 简单使用:拷贝两个配置文件,IKAnalyzer.cfg.xml,stopword.dic拷贝一个jar包
// IKAnalyzer2012_V5.jar
// 扩展词,停止词
// 注意:打开方式,不要使用其他的,
//直接使用eclipse的text Editor,
//修改以后要刷新一下让项目重新编译(有时候需要有时候不需要刷新)
@Test
public void testIKAnalyzer() throws Exception {
//true 粗密度分词(智能分词) false 细密度分词
testAnalyzer(new IKAnalyzer(false), str);
}
索引的添删改
经过之前的分析,我们知道对索引的操作统一使用IndexWriter。测试代码如下:
// 数据源
private String doc1 = "hello world";
private String doc2 = "hello java world";
private String doc3 = "hello lucene world";
// 索引库目录
private String indexPath = "F:\\ecworkspace\\lucene\\indexCRUD";
@Test
public void createIndex() throws IOException, ParseException {
/**
* 准备工作
*/
// 索引目录
Directory d = FSDirectory.open(Paths.get(indexPath));
// 词法分析器
Analyzer analyzer = new StandardAnalyzer();
// 写操作核心配置对象
IndexWriterConfig conf = new IndexWriterConfig(analyzer);
conf.setOpenMode(OpenMode.CREATE);
// 写操作核心对象
IndexWriter indexWriter = new IndexWriter(d, conf);
System.out.println(indexWriter);
/**
* 操作
*/
Document document1 = new Document();
document1.add(new TextField("id", "1", Store.YES));
document1.add(new TextField("name", "doc1", Store.YES));
document1.add(new TextField("content", doc1, Store.YES));
indexWriter.addDocument(document1);
Document document2 = new Document();
document2.add(new TextField("id", "2", Store.YES));
document2.add(new TextField("name", "doc2", Store.YES));
document2.add(new TextField("content", doc2, Store.YES));
indexWriter.addDocument(document2);
Document document3 = new Document();
document3.add(new TextField("id", "3", Store.YES));
document3.add(new TextField("name", "doc3", Store.YES));
document3.add(new TextField("content", doc3, Store.YES));
indexWriter.addDocument(document3);
/**
* 收尾
*/
indexWriter.commit();
indexWriter.close();
searchIndex();
}
@Test
public void del() throws IOException, ParseException{
/**
* 准备工作
*/
// 索引目录
Directory d = FSDirectory.open(Paths.get(indexPath));
// 词法分析器
Analyzer analyzer = new StandardAnalyzer();
// 写操作核心配置对象
IndexWriterConfig conf = new IndexWriterConfig(analyzer);
// 写操作核心对象
IndexWriter indexWriter = new IndexWriter(d, conf);
System.out.println(indexWriter);
//删除所有
//indexWriter.deleteAll();
//第一种
// QueryParser qpParser = new QueryParser("id", analyzer);
// Query query = qpParser.parse("1");
// indexWriter.deleteDocuments(query);
//第二种
indexWriter.deleteDocuments(new Term("id", "1"));
indexWriter.commit();
indexWriter.close();
searchIndex();
}
@Test
public void update() throws IOException, ParseException{
/**
* 准备工作
*/
// 索引目录
Directory d = FSDirectory.open(Paths.get(indexPath));
// 词法分析器
Analyzer analyzer = new StandardAnalyzer();
// 写操作核心配置对象
IndexWriterConfig conf = new IndexWriterConfig(analyzer);
// 写操作核心对象
IndexWriter indexWriter = new IndexWriter(d, conf);
System.out.println(indexWriter);
Document doc = new Document();
doc.add(new TextField("id", "2", Store.YES));
doc.add(new TextField("name", "doc2", Store.YES));
doc.add(new TextField("content", "修改后 -的doc2", Store.YES));
indexWriter.updateDocument(new Term("id","2"), doc );
/*等价于
indexWriter.deleteDocuments(new Term("id", "2"));
indexWriter.addDocument(doc);
*/
indexWriter.commit();
indexWriter.close();
searchIndex();
}
@Test
public void searchIndex() throws IOException, ParseException {
// 索引目录
Directory d = FSDirectory.open(Paths.get(indexPath));
// 词法分析器
Analyzer analyzer = new StandardAnalyzer();
// 创建索引的读写对象
IndexReader r = DirectoryReader.open(d);
// 创建核心对象
IndexSearcher indexSearcher = new IndexSearcher(r);
// 查询解析器
// 参数1:默认查询的字段
// 参数2:分词器
QueryParser queryParser = new QueryParser("content", analyzer);
String queryString = "*:*";
Query query = queryParser.parse(queryString);
// 调用核心对象的search方法
// 参数query: 查询对象
// 参数 n : 前n条
TopDocs topDocs = indexSearcher.search(query, 50);
System.out.println("一共查询到的数量:" + topDocs.totalHits);
// 获得数据集合
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
for (ScoreDoc scoreDoc : scoreDocs) {
// 获取文档ID
int docId = scoreDoc.doc;
// 通过docId获取Document
Document doc = indexSearcher.doc(docId);
System.out.println("id="+doc.get("id")+",name=" + doc.get("name") + ",content=" + doc.get("content"));
}
}
今天就到这里