构建索引
1.创建Directory对象,指定索引库存放位置
2.创建Analyzer对象,指定分析器类型
3.基于1和2创建IndexWriter对象
4.创建Document对象
5.创建Field对象,并将Field对象添加到Document对象中
6.使用IndexWriter对象将Document对象写入到索引库
7.关闭IndexWriter对象
Directory对象
Lucene中,Directory抽象类有两个子类,分别是RAMDirectory和FSDirectory。
-
SimpleFSDirectory
类:FSDirectory的简单实现,并发能力有限,遇到多线程读同一个文件时会遇到瓶颈。 -
NIOFSDirectory
类:通过java.nio’s FileChannel实行定位读取,支持多线程读(默认情况下是线程安全的)。该类仅使用FileChannel进行读操作,写操作则是通过FSIndexOutput实现。 注意:NIOFSDirectory 不适用于Windows系统,另外如果一个访问该类的线程,在IO阻塞时被interrupt或cancel,将会导致底层的文件描述符被关闭,后续的线程再次访问NIOFSDirectory时将会出现ClosedChannelException异常,此种情况应用SimpleFSDirectory代替。 -
RAMDirectory
类:常驻内存的Directory实现方式。默认通过SingleInstanceLockFactory(单实例锁工厂)进行锁的实现。该类不适合大量索引的情况。另外也不适用于多线程的情况。 在索引数据量大的情况下建议使用MMapDirectory代替。RAMDirectory是Directory抽象类在使用内存最为文件存储的实现类,其主要是将所有的索引文件保存到内存中。这样可以提高效率。但是如果索引文件过大的话,则会导致内存不足,因此,小型的系统推荐使用,如果大型的,索引文件达到G级别上,推荐使用FSDirectory。 -
MMapDirectory
类:通过内存映射进行读,通过FSIndexOutput进行写的FSDirectory实现类。使用该类时要保证用足够的虚拟地址空间。另外当通过IndexInput的close方法进行关闭时并不会立即关闭底层的文件句柄,只有GC进行资源回收时才会关闭。
Analyzer对象
WhitespaceAnalyzer
类:仅根据空白字符(whitespace)进行分词。KeywordAnalyzer
类:不做任何分词,把整个原始输入作为一个token。所以可以看到输出只有1个token,就是原始句子。SimpleAnalyzer
类:根据非字母(non-letters)分词,并且将token全部转换为小写。所以该分词的输出的terms都是由小写字母组成的。StopAnalyzer
类:在SimpleAnalyzer的基础上增加了去除StopWords的功能。StandardAnalyzer
类:基于JFlex进行语法分词(中文按字分,英文按空格分),然后删除停用词,并且将token全部转换为小写。ChineseAnalyzer
类:性能类似于StandardAnalyzer,缺点是不支持中英文混和分词。CJKAnalyzer
类:chedong写的CJKAnalyzer的功能在英文处理上的功能和StandardAnalyzer相同,但是在汉语的分词上,不能过滤掉标点符号,即使用二元切分。
Field对象
三大类属性:
- 是否分析:是否对域的内容进行分词处理。前提是我们要对域的内容进行查询。
- 是否索引:将Field分析后的词或整个Field值进行索引,只有索引方可搜索到。比如:商品名称、商品简介分析后进行索引,订单号、身份证号不用分析但也要索引,这些将来都要作为查询条件。
- 是否存储:将Field值存储在文档中,存储在文档中的Field才可以从Document中获取。比如:商品名称、订单号,凡是将来要从Document中获取的Field都要存储。
Field的各个子类就是实现了对不同类型字段的存储,同时选择了不同的字段属性,这里列举几个常用的:
TextField
:存储字符串类型的数据。indexing+analyze;默认不存储原始数据。适用于需要全文检索的数据,比如邮件内容,网页内容等。StringField
:存储字符串类型的数据。indexing但不analyze,即整个字符串就是一个token;默认不存储原始数据。适用于文章标题、人名、ID等只需精确匹配的字符串。IntPoint
,LongPoint
,FloatPoint
,DoublePoint
:用于存储各种不同类型的数值型数据。indexing;默认不存储原始数据。适用于数值型数据的存储。
执行搜索
https://www.cnblogs.com/leeSmall/p/9027172.html
1. 创建一个Directory对象,也就是索引库存放的位置
2. 创建一个DirectoryReader对象,需要指定Directory对象
3. 创建一个IndexSearcher对象,需要指定IndexReader对象
4. 创建Query对象,并执行查询
6. 返回查询结果,遍历查询结果并输出
7. 关闭DirectoryReader对象
Query对象
TermQuery
:单关键字精确查询,注意TermQuery直接将搜索文本提交进行搜索,不进行analyze操作。
TermQuery tq = new TermQuery(new Term(“name", “thinkpad"));
-
RangeQuery
:范围查询 -
PhraseQuery
:多关键字查询 -
MultiPhraseQuery
:多关键字查询,支持同位置多个词的OR匹配 -
BooleanQuery
:多条件查询
// 布尔查询
Query query1 = new TermQuery(new Term(filedName, "thinkpad"));
query1 = new TermQuery(new Term(filedName, "thinkpad"))
Query query2 = new TermQuery(new Term("simpleIntro", "英特尔"));
BooleanQuery.Builder booleanQueryBuilder = new BooleanQuery.Builder();
booleanQueryBuilder.add(query1, Occur.SHOULD);
booleanQueryBuilder.add(query2, Occur.MUST);
BooleanQuery booleanQuery = booleanQueryBuilder.build();
解析器
- 传统的解析器:
QueryParser
和MultiFieldQueryParser
// 传统查询解析器-多默认字段
QueryParser parser = new QueryParser("defaultFiled", analyzer);
Query query = parser.parse("query String");
// 传统查询解析器-多默认字段
String[] multiDefaultFields = { "name", "type", "simpleIntro" };
MultiFieldQueryParser multiFieldQueryParser = new MultiFieldQueryParser(multiDefaultFields, analyzer);
// 设置默认的组合操作,默认是 OR
multiFieldQueryParser.setDefaultOperator(Operator.OR);
Query query4 = multiFieldQueryParser.parse("笔记本电脑 AND price:1999900");
- 基于新的 flexible 框架的解析器:
StandardQueryParser
StandardQueryParser queryParserHelper = new StandardQueryParser(analyzer);
// 设置默认字段
// queryParserHelper.setMultiFields(CharSequence[] fields);
// queryParserHelper.setPhraseSlop(8);
// Query query = queryParserHelper.parse("a AND b", "defaultField");
Query query5 = queryParserHelper.parse("(\"联想笔记本电脑\" OR simpleIntro:英特尔) AND type:电脑 AND price:1999900","name");