简介
分词器:采集到的数据会存储到Document对象的Field域中,分词器就是将Document中Field的value 值切分成一个一个的词。
停用词:停用词是为节省存储空间和提高搜索效率,搜索程序在索引页面或处理搜索请求时会自动忽略某 些字或词,这些字或词即被称为Stop Words(停用词)。比如语气助词、副词、介词、连接词等,通常自 身并无明确的意义,只有将其放入一个完整的句子中才有一定作用,如常见的“的”、“在”、“是”、“啊” 、 a、an、the 等。
扩展词: 扩展词 就是分词器默认不会切出的词 但我们希望分词器切出这样的词 。 过滤:包括去除标点符号过滤、去除停用词过滤(的、是、a、an、the等)、大写转小写、词的形还原 (复数形式转成单数形参、过去式转成现在式。。。)等。
默认使用的是标准分析器StandardAnalyzer
查询分析器效果
使用Analyzer对象的tokenStream方法返回一个TokenStream对象.词对象中包含了最终分词结果.
实现步骤
- 创建一个Analyzer对象,StandardAnalyzer对象
- 使用分析器对象的tokenStream方法获得一个TokenStream对象
- 向TokenStream对象中设置一个引用,相当于一个指针
- 调用while循环遍历TokenStream对象
-
分析器
@Test
public void testTokenStream() throws IOException {
//1. 创建一个Analyzer对象,StandardAnalyzer对象
StandardAnalyzer analyzer = new StandardAnalyzer();
//Analyzer analyzer = new IKAnalyzer();
//2. 使用分析器对象的tokenStream方法获得一个TokenStream对象, 域名称,分析的文本内容
TokenStream tokenStream = analyzer.tokenStream("", "数据库like查询和全文检索的区别");
//3. 向TokenStream对象中设置一个引用,相当于一个指针
CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
//4. 调用TokenStream对象的rest方法.如果不调用抛异常
tokenStream.reset();
//5. 调用while循环遍历TokenStream对象
while (tokenStream.incrementToken()) {
System.out.println(charTermAttribute.toString());
}
//6. 关闭TokenStream对象
tokenStream.close();
/**
* 输出
* 数
* 据
* 库
* like
* 查
* 询
* 和
* 全
* 文
* 检
* 索
* 的
* 区
* 别
*/
}
扩展ik中文分词
IKAnalyze的使用方法
- 把IKAnalyzer的jar包添加到工程中
- 把配置文件和扩展词典添加到工程的classpath下
注意:hotword.dic和ext_stopword.dic文件的格式为UTF-8,注意是无BOM 的UTF-8编码。也就是说禁止使用windows记事本编辑扩展词典文件
扩展词典: 添加一些新词
停用词词典: 无意义的词或者敏感词汇
使用方法:
第一步:把jar包添加到工程中
第二步:把配置文件和扩展词典和停用词词典添加到classpath下
注意:hotword.dic和ext_stopword.dic文件的格式为UTF-8,注意是无BOM 的UTF-8编码。
xml可以配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">hotword.dic;</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords">stopword.dic;</entry>
</properties>
@Test
public void testTokenStream() throws IOException {
//1. 创建一个分词对象
IKAnalyzer analyzer = new IKAnalyzer();
//2. 使用分析器对象的tokenStream方法获得一个TokenStream对象, 域名称,分析的文本内容
TokenStream tokenStream = analyzer.tokenStream("", "1.2.1全文检索");
//3. 向TokenStream对象中设置一个引用,相当于一个指针
CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
//4. 调用TokenStream对象的rest方法.如果不调用抛异常
tokenStream.reset();
//5. 调用while循环遍历TokenStream对象
while (tokenStream.incrementToken()) {
System.out.println(charTermAttribute.toString());
}
//6. 关闭TokenStream对象
tokenStream.close();
}
扩展字段
文
停用词典
1.2
输出
加载扩展词典:hotword.dic
加载扩展停止词典:stopword.dic
1.2.1
全文
文
检索
创建索引使用ik分词
IndexWriterConfig那指定ik
@Test
public void testCreateIndex() throws Exception {
// 1. 采集数据 和 之前完全相同
List<Book> bookList = new ArrayList<Book>();
Book booka = new Book();
booka.setId(1);
booka.setDesc("数据库like查询和全文检索的区别");
booka.setName("lucene");
booka.setPrice(100.45f);
bookList.add(booka);
// 2. 创建Document文档对象
List<Document> documents = new ArrayList<>();
for (Book book : bookList) {
Document document = new Document();
// IntPoint 分词 索引 不存储 存储结合 StoredField
Field id = new IntPoint("id", book.getId());
Field id_v = new StoredField("id", book.getId());
// 分词、索引、存储 TextField
Field name = new TextField("name", book.getName(), Field.Store.YES);
// 分词、索引、不存储 但是是数字类型,所以使用FloatPoint
Field price = new FloatPoint("price", book.getPrice());
// 分词、索引、存储 TextField 为了看到分词效果设置成存储
Field desc = new TextField("desc", book.getDesc(), Field.Store.YES);
// 将field域设置到Document对象中
document.add(id);
document.add(id_v);
document.add(name);
document.add(price);
document.add(desc);
documents.add(document);
}
//3.创建StandardAnalyzer 分词器 对文档进行分词 把 StandardAnalyzer 变成 IKAnalyer
//Analyzer analyzer = new StandardAnalyzer();
Analyzer analyzer = new IKAnalyzer();
// 创建Directory 和 IndexWriterConfig 对象
Directory directory = FSDirectory.open(Paths.get("/Users/xiajiandong/Desktop/luceneTest/index5"));
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
// 4.创建IndexWriter 写入对象
IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
// 添加文档对象
for (Document doc : documents) {
indexWriter.addDocument(doc);
}
// 释放资源
indexWriter.close();
}
源码
@Override
protected TokenStreamComponents createComponents(final String fieldName) {
final StandardTokenizer src = new StandardTokenizer();
src.setMaxTokenLength(maxTokenLength);
TokenStream tok = new LowerCaseFilter(src);
tok = new StopFilter(tok, stopwords);
return new TokenStreamComponents(src, tok) {
@Override
protected void setReader(final Reader reader) {
// So that if maxTokenLength was changed, the change takes
// effect next time tokenStream is called:
src.setMaxTokenLength(StandardAnalyzer.this.maxTokenLength);
super.setReader(reader);
}
};
}
Tokenizer就是分词器,负责将reader转换为语汇单元即进行分词处理,Lucene提供了很多的分词器, 也可以使用第三方的分词,比如IKAnalyzer一个中文分词器。
TokenFilter是分词过滤器,负责对语汇单元进行过滤,TokenFilter可以是一个过滤器链儿,Lucene提 供了很多的分词器过滤器,比如大小写转换、去除停用词等。
如下图是语汇单元的生成过程:
创建一个Tokenizer分词器,经过三个TokenFilter生成语汇单元Token。
Tokenizer —->TokenFilter(标准过滤)—->TokenFilter(大小写过滤)—->TokenFilter(停用词过滤)—->Tokens
比如下边的文档经过分析器分析如下:
原文档内容:
Lucene is java full text search lib
分析后得到的多个语汇单元:
lucene java full text search lib
注意:搜索使用的分词器要和索引使用的分词器一致。