2. 配置开发环境
2.1 Lucene下载
http://lucene.apache.org
版本:7.7.1
IDE:eclipse
2.2 创建工程
新建名为lucene的项目
导入jar包:
必须jar包:
commons-io-2.6.jar
lucene-analyzers-common-7.7.1.jar
lucene-core-7.7.1.jar
lucene-memory-7.7.1.jar
可选jar包:
IK分词器
IK-Analyzer-7.2.1.jar
关键词高亮插件包:
lucene-highlighter-7.7.1.jar
lucene-queries-7.7.1.jar
lucene-queryparser-7.7.1.jar
lucene-join-7.7.1.jar
创建LuceneStarting类并写创建索引方法:
设置索引存放位置为:F:/testData/luceneIndex
测试文件存放位置为:F:/testData/lucenetestdata,可以自己弄几个文档测试一下。
2.3 实现步骤
第一步:创建一个java工程,并导入jar包。第二步:创建一个indexwriter对象。
1)指定索引库的存放位置Directory对象
2)指定一个分析器,对文档内容进行分析。
第三步:创建 document对象。
第三步:创建eld 对象,将field添加到document对象中。
第四步:使用indexwriter 对象将document对象写入索引库,此过程进行索引创建。并将索引和document对象写入索引库。
第五步:关闭Indexwriter对象。
Field域的属性:
是否分析:是否对域的内容进行分词处理。前提是我们要对域的内容进行查询。
是否索引:将Field分析后的词或整个Field值进行索引,只有索引方可搜索到。比如:商品名称、商品简介分析后进行索引,订单号、身份证号不用分析但也要索引,这些将来都要作为查询条件。
是否存储:将Field值存储在文档中,存储在文档中的Field 才可以从Document中获取。
比如:商品名称、订单号,凡是将来要从Document 中获取的Field 都要存储。
/**
* @ClassName: LuceneStarting
* @Description: lucen入门
* 创建索引
* 查询索引
* @author: guqing
* @date: 2019年3月10日 下午2:14:53
*
*/
public class LuceneStarting {
/**
* @throws IOException
* @Description: 测试创建索引
* @param:
* @return: void
* @throws
*/
@Test
public void testCreateIndex() throws IOException{
//第一步:创建一个java工程,并导入jar包
//第二步:创建一个indexwriter对象
// (1)指定索引库存放位置Directory对象
// (2)指定一个分析器,对文档内容进行分析
//File indexrepository_file = new File("F:/testData/luceneIndex");
//Path path = indexrepository_file.toPath();
//Directory directory = FSDirectory.open(path);//使用path
//索引建立在内存中
//Directory directory01=new RAMDirectory();
//设置索引存放位置
Path path = FileSystems.getDefault().getPath("F:/testData/luceneIndex");
Directory directory = FSDirectory.open(path);
//Analyzer analyzer = new StandardAnalyzer();
Analyzer analyzer = new IKAnalyzer();
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
IndexWriter inedxWriter = new IndexWriter(directory, indexWriterConfig);
/*
* 第三步:创建document对象
* Field域的属性:
* 是否分析:是否对域的内容进行分词处理,前提是我们要对域的内容进行查询
* 是否索引:将Field分析后的词或整个Field值进行索引,只有索引方可以搜索到
* 比如商品名称商品简介分析后进行索引
* 是否存储:将Field值存储到文档中,存储到Field才可以从document中获取,
* 是否存储的标准是否要展示给用户看
* --------------------------------------------------------------------------
* Field类 数据类型 是否分析 是否索引 是否存储
* StringField 字符串 N Y Y/N
* LongField Long型 Y Y Y/N
* StoredField 支持多种类型 N N Y
* TextField 字符串或流 Y Y Y/N
* LongField现已废弃由LongPoint取代,所有数值类型都是Point
*/
File file = new File("F:/testData/lucenetestdata");
File[] listFiles = file.listFiles();
for(File listFile : listFiles){
Document document = new Document();
//文件名称
String fileName = listFile.getName();
//创建域用于存储,域名 域值 是否存储
Field fileNameField = new TextField("fileName", fileName, Store.YES);
//文件大小
long fileSize = FileUtils.sizeOf(listFile);
Field fileSizeField = new LongPoint("fileSize", fileSize);//new StoredField("fileSize", fileSize);
//文件路径
String filePath = listFile.getAbsolutePath();
Field filePathField = new StoredField("filePath", filePath);
//文件内容
String fileContent = FileUtils.readFileToString(listFile, "GBK");//txt文件是GBK编码
Field fileContentField = new TextField("fileContent", fileContent, Store.YES);
//第四步:创建field对象,将field添加到document
document.add(fileNameField);
document.add(fileSizeField);
document.add(filePathField);
document.add(fileContentField);
//第五步:使用indexwriter对象将document对象写入索引库,此过程进行索引创建,并将索引和document对象写入索引库
inedxWriter.addDocument(document);
}
//第六步:关闭IndexWriter对象
inedxWriter.close();
}
2.4 精确查询方法:
第一步:创建一个Directory对象,也就是索引库存放的位置。
第二步:创建一个indexReader对象,需要指定Directory对象。
第三步:创建一个indexsearcher对象,需要指定IncdexReader对象第四步:创建一个TermQuery对象,指定查询的域和查询的键词。
第五步:执行查询。
第六步:返回查询结果。遍历查询结果并输出。第七步:关闭IndexReader 对象
/**
* @Description: 分词搜索
* @param: @throws IOException
* @return: void
* @throws
*/
@Test
public void testSearch() throws IOException{
//第一步:创建一个Directory对象,也就是索引库存放的位置
Path path = FileSystems.getDefault().getPath("F:/testData/luceneIndex");
Directory directory = FSDirectory.open(path);
//第二步:创建一个indexReader对象,需要执行Directory对象
IndexReader indexReader = DirectoryReader.open(directory);
//第三步:创建一个indexSearcher对象,需要指定IndexReader对象
IndexSearcher indexSearch = new IndexSearcher(indexReader);
//第四步:创建一个TermQuery对象,指定查询的域和查询的关键词,精准查询
Query query = new TermQuery(new Term("fileName", "ant"));
TopDocs topDoecs = indexSearch.search(query, 4);
//第五步:返回查询
ScoreDoc[] scoreDocs = topDoecs.scoreDocs;
//第六步:返回查询结果,遍历查询结果并输出
for(ScoreDoc scoreDoc : scoreDocs){
int docID = scoreDoc.doc;
Document document = indexSearch.doc(docID);
String fileName = document.get("fileName");
String fileSize = document.get("fileSize");
String filePath = document.get("filePath");
String fileContent = document.get("fileContent");
System.out.println("--------------->fileName:" + fileName +",fileSize:" + fileSize + ",filePath:" + filePath);
}
//第七步:关闭IndexReader对象
indexReader.close();
}
@Test
public void testTokenStream() throws Exception {// 创建一个分析器对象
//Analyzer analyzer = new StandardAnalyzer();
//Analyzer analyzer = new CJKAnalyzer();
//Analyzer analyzer = new SmartChineseAnalyzer();
Analyzer analyzer = new IKAnalyzer();
// 获得tokenStream对象
// 第一个参数:域名,可以随便给一个
// 第二个参数:要分析的文本内容
File file = new File("F:/testData/lucenetestdata/网易热评.txt");
String content = FileUtils.readFileToString(file, "GBK");
TokenStream tokenStream = analyzer.tokenStream("test",content);
// 添加一个引用,可以获得每个关键词
CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
// 添加一个偏移量的引用,记录了关键词的开始位置以及结束位置
OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
// 将指针调整到列表的头部
tokenStream.reset();
// 遍历关键词列表,通过incrementToken方法判断列表是否结束
while (tokenStream.incrementToken()) {
// 关键词的起始位置
System.out.println("start->" + offsetAttribute.startOffset());
// 取关键词
System.out.println(charTermAttribute);
// 结束位置
System.out.println("end->" + offsetAttribute.endOffset());
System.out.println("\n");
}
tokenStream.close();
}
2.5 支持中文分词
分析其(Analyzer)的执行结果
@Test
public void testTokenStream() throws Exception {// 创建一个分析器对象
//标砖分词器
Analyzer analyzer = new StandardAnalyzer();
//CJK分词器,Lucene自带
//Analyzer analyzer = new CJKAnalyzer();
//SmartChinese分词器
//Analyzer analyzer = new SmartChineseAnalyzer();
//IK分词器
//Analyzer analyzer = new IKAnalyzer();
// 获得tokenStream对象
// 第一个参数:域名,可以随便给一个
// 第二个参数:要分析的文本内容
File file = new File("F:/testData/lucenetestdata/网易热评.txt");
String content = FileUtils.readFileToString(file, "GBK");
TokenStream tokenStream = analyzer.tokenStream("test",content);
// 添加一个引用,可以获得每个关键词
CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
// 添加一个偏移量的引用,记录了关键词的开始位置以及结束位置
OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
// 将指针调整到列表的头部
tokenStream.reset();
// 遍历关键词列表,通过incrementToken方法判断列表是否结束
while (tokenStream.incrementToken()) {
// 关键词的起始位置
System.out.println("start->" + offsetAttribute.startOffset());
// 取关键词
System.out.println(charTermAttribute);
// 结束位置
System.out.println("end->" + offsetAttribute.endOffset());
System.out.println("\n");
}
tokenStream.close();
}
使用标准分词器对中文的分词效果是单个词:
start->0 小 end->1
start->1 时 end->2
start->2 候 end->3
start->3 一 end->4
start->4 直 end->5
start->5 幻 end->6
start->6 想 end->7
start->8 长 end->9
start->9 大 end->10
start->10 的 end->11
start->11 世 end->12
start->12 界 end->13
start->13 有 end->14
start->14 多 end->15
start->15 不 end->16
start->16 一 end->17
start->17 样 end->18
其他分词器可以自己测试,效果不是很好,IK分词器支持扩展词库,分词效果为:
start->0
小时候
end->3
start->0
小时
end->2
start->4
直
end->5
start->5
幻想
end->7
start->8
长大
end->10
start->11
世界
end->13
start->14
多不
end->16
start->15
不一样
end->18
start->17
样
end->18
导入jar包:IK-Analyzer-7.2.1.jar
加入IK分词器的配置文件:IKAnalyzer.cfg.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;internetword.dic;phrase.dic;chatword.dic;</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords">stopword.dic;</entry>
</properties>
其中stopword.dic
(停止词)和hotword.dic
(热词)为必须导入否则会报找不到文件错误,还可以额外添加一些词库,如:internetword.dic
、phrase.dic
、chatword.dic
stopword.dic例如:(详细见文件)
able
about
above
according
hereby
herein
i’d
ie
if
together
too
took
toward
towards
ous
very
via
viz
vs
want
wants
was
wasn’t
way
we
we’d
welcome
zt
ZT
zz
ZZ
一
一下
一些
一切
一则
一天
一定
一方面
一般
一起
一边
一面
万一
上下
上升
上去
上来
上述
上面
下列
下去
下来
下面
不一
不怕
不惟
不成
不拘
不敢
不断
不是
不比
不然
2.6 索引库使用时机
索引时使用Analyzer
输入关键字进行搜索,当需要让该关键字与文档域内所包含的词进行匹配时需要对文档域内容进行分析,需要经过Analyzer分析器处理生成语汇单元(Token)。分析器分析的对象是文档中的Field域。当Field的属性tokenized(是否分词)为true时会对Field值进行分析,如下图:
对于一些Field可以不用分析:
1、不作为查询条件的内容,比如文件路径
2、不是匹配内容中的词而匹配Field的整体内容,比如订单号、身份证号等。
搜索时使用Analyzer
对搜索关键字进行分析和索引分析一样,使用Analyzer对搜素关键字进行分析、分词处理,使用分析后每个词语进行搜索。比如:搜索关键字:spring web,经过分析器进行分词,得出:spring web拿词去索引词典表查找,找到索引链接到Document,解析Document内容。对于匹配整体Field域的查询可以在搜索时不分析,比如根据订单号、身份证号查询等。
注意:搜索使用的分析器要和索引使用的分析器一致I
2.7 索引库的维护
2.7.1 索引库的添加
起步已经包括了索引添加
2.7.2 索引库的删除
public IndexWriter getIndexWriter() throws IOException {
//第一步:创建一个Directory对象,也就是索引库存放的位置
Path path = FileSystems.getDefault().getPath("F:/testData/luceneIndex");
Directory directory = FSDirectory.open(path);
Analyzer analyzer = new IKAnalyzer();
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
IndexWriter inedxWriter = new IndexWriter(directory, indexWriterConfig);
return inedxWriter;
}
以上的get方法用于获得IndexWriter
,以便不需要重复的写这些代码。
2.7.2.1 删除全部索引:
//全部删除
@Test
public void testDeleteIndex() throws IOException{
IndexWriter inedxWriter = getIndexWriter();
inedxWriter.deleteAll();//删除全部
inedxWriter.close();
}
2.7.2.2 根据条件删除:
//根据条件
@Test
public void testDeleteIndexByCondition() throws IOException{
IndexWriter inedxWriter = getIndexWriter();
Query query = new TermQuery(new Term("fileName", "apache"));
inedxWriter.deleteDocuments(query);
inedxWriter.close();
}
2.7.2.3 恢复删除:
//恢复,从回收站恢复
@Test
public void testRecover() throws Exception{
IndexWriter indexWriter = getIndexWriter();
indexWriter.rollback();
indexWriter.close();
}
2.7.3 索引库修改:
//修改
@Test
public void testUpdateIndex() throws IOException{
IndexWriter inedxWriter = getIndexWriter();
Document document = new Document();
document.add(new TextField("fileName", "测试文件名称", Store.YES));
document.add(new TextField("fileContent", "测试文件内容", Store.YES));
//以lucene为关键词的就更新,先删除lucene索引,在添加document
inedxWriter.updateDocument(new Term("fileName", "ant"), document);
inedxWriter.close();
}
2.7.4 Lucene索引库的查询(重点)
用于输出查询结果的公共方法:
//执行查询并打印结果
public void printResult(IndexSearcher indexSearcher,Query query,Integer num) throws Exception{
//使用排序
//Sort sort =new Sort();
//SortField f = new SortField("fileSize",Type.LONG,true); // 按照fileSize字段排序,true表示降序
//sort.setSort(f);
// 多个条件排序
// Sort sort = new Sort();
// SortField f1 = new SortField("createdate", SortField.DOC, true);
// SortField f2 = new SortField("bookname", SortFiedl.INT, false);
// sort.setSort(new SortField[] { f1, f2 });
//高亮显示start
//算分
QueryScorer scorer=new QueryScorer(query);
//显示得分高的片段
Fragmenter fragmenter=new SimpleSpanFragmenter(scorer);
//设置标签内部关键字的颜色
//第一个参数:标签的前半部分;第二个参数:标签的后半部分。
SimpleHTMLFormatter simpleHTMLFormatter=new SimpleHTMLFormatter("<b><font color='red'>","</font></b>");
//第一个参数是对查到的结果进行实例化;第二个是片段得分(显示得分高的片段,即摘要)
Highlighter highlighter=new Highlighter(simpleHTMLFormatter, scorer);
//设置片段
highlighter.setTextFragmenter(fragmenter);
//高亮显示end
TopDocs topDocs = indexSearcher.search(query, num);
ScoreDoc[] scoreDocs = topDocs.scoreDocs;//文档id数组
for (ScoreDoc scoreDoc : scoreDocs) {
//根据id获取文档
Document document = indexSearcher.doc(scoreDoc.doc);
//获取结果,没有存储的是null,比如内容
String fileSize = document.get("fileSize");
String filePath = document.get("filePath");
String name = document.get("fileName");
String fileContent = document.get("fileContent");
if(name!=null){
//把全部得分高的摘要给显示出来
//第一个参数是对哪个参数进行设置;第二个是以流的方式读入
TokenStream tokenStream = new IKAnalyzer().tokenStream("fileName", new StringReader(name));
TokenStream tokenStream1 = new IKAnalyzer().tokenStream("fileContent", new StringReader(fileContent));
//获取最高的片段
System.out.println("高亮文档名: "+highlighter.getBestFragment(tokenStream, name));
System.out.println("高亮文件内容: "+highlighter.getBestFragment(tokenStream1, fileContent));
}
System.out.println("fileName:"+name+",fileSize:"+fileSize+",filePath:"+filePath);
System.out.println("-------------------");
}
}
以上使用到Lucene Highlight高亮显示jar包,具体导入已经在第一节说过了。
获取IndexSearcher的公共方法:
public IndexSearcher getIndexSearcher() throws IOException{
//第一步:创建一个Directory对象,也就是索引库存放的位置
Path path = FileSystems.getDefault().getPath("F:/testData/luceneIndex");
Directory directory = FSDirectory.open(path);
//第二步:创建一个indexReader对象,需要执行Directory对象
IndexReader indexReader = DirectoryReader.open(directory);
//第三步:创建一个indexSearcher对象,需要指定IndexReader对象
IndexSearcher indexSearch = new IndexSearcher(indexReader);
return indexSearch;
}
2.7.4.1 查询全部
@Test
public void testMatchAllDocsQuery() throws Exception{
IndexSearcher indexSearch = getIndexSearcher();
//创建查询器
Query query = new MatchAllDocsQuery();
//打印查询结果
printResult(indexSearch,query,10);
//关闭资源
indexSearch.getIndexReader().close();
}
2.7.4.2 精确查询及指定范围查询
//数值精确查询
@Test
public void testNumberSearch() throws Exception{
IndexSearcher indexSearch = getIndexSearcher();
//数字精确查询, 查询大小为1503b和1401b的两个文件,也可以传一个List
//新版本中数值都使用Point进行查询,原理的Numic被废弃
Query query = LongPoint.newSetQuery("fileSize", 1503L, 1401L);//不定参数
//范围查询:查询fileSize范围为 [500字节,12018字节]的文档
Query query1 = LongPoint.newRangeQuery("fileSize", 500L, 12018L);
printResult(indexSearch,query1,10);
//关闭资源
indexSearch.getIndexReader().close();
}
字符串范围查询:
/**
* TermRangeQuery是用于字符串范围查询的,既然涉及到范围必然需要字符串比较大小,
* 字符串比较大小其实比较的是ASC码值,即ASC码范围查询。
* 一般对于英文来说,进行ASC码范围查询还有那么一点意义,
* 中文汉字进行ASC码值比较没什么太大意义,所以这个TermRangeQuery了解一下就行
*/
@Test
public void testTermRangeQuery() throws Exception{
IndexSearcher indexSearcher = getIndexSearcher();
String lowerTermString = "想";//范围的下端的文字,后面boolean为真,对应值为闭区间
String upperTermString = "有时";//范围的上限内的文本,后面boolean为真,对应值为闭区间
//lucene 使用 BytesRef 在索引中表示utf-8编码的字符,此类含有偏移量_长度以及byte数组,可使用utf8toString API转换字符串
Query query=new TermRangeQuery("fileContent",new BytesRef(lowerTermString),new BytesRef(upperTermString),true,true);
printResult(indexSearcher,query,10);
//关闭reader
indexSearcher.getIndexReader().close();
}
2.7.4.3 布尔查询
/**
* BooleanQuery也是实际开发过程中经常使用的一种Query。
* 它其实是一个组合的Query,在使用时可以把各种Query对象添加进去并标明它们之间的逻辑关系。
* 所有的Query都可以通过booleanQUery组合起来
* BooleanQuery本身来讲是一个布尔子句的容器,它提供了专门的API方法往其中添加子句,
* 并标明它们之间的关系
*/
@Test
public void testBoostQuery() throws Exception{
IndexSearcher indexSearcher = getIndexSearcher();
//组合条件
Query query1=new TermQuery(new Term("fileContent","小时候"));
Query query2=new TermQuery(new Term("fileContent","大海"));
//相当于一个包装类,将 Query 设置 Boost 值 ,然后包装起来。
//再通过复合查询语句,可以突出 Query 的优先级
BoostQuery query=new BoostQuery(query2, 2f);
//创建BooleanQuery.Builder
BooleanQuery.Builder builder=new BooleanQuery.Builder();
//添加逻辑
/**
* 1.MUST和MUST:取得两个查询子句的交集。 and
2.MUST和MUST_NOT:表示查询结果中不能包含MUST_NOT所对应得查询子句的检索结果。
3.SHOULD与MUST_NOT:连用时,功能同MUST和MUST_NOT。
4.SHOULD与MUST连用时,结果为MUST子句的检索结果,但是SHOULD可影响排序。
5.SHOULD与SHOULD:表示“或”关系,最终检索结果为所有检索子句的并集。
6.MUST_NOT和MUST_NOT:无意义,检索无结果。
*/
builder.add(query1, Occur.SHOULD);// 文件内容不包含词语,但是内容必须包含
builder.add(query, Occur.SHOULD);
//build query
BooleanQuery booleanQuery=builder.build();
printResult(indexSearcher,booleanQuery,10);
//关闭reader
indexSearcher.getIndexReader().close();
}
2.7.4.4 匹配查询
前缀匹配查询:
/**
* @Description: 查询文件名以 小 开头的索引 前缀匹配查询
* @param: @throws Exception
* @return: void
* @throws
*/
@Test
public void testPrefixQuery() throws Exception{
IndexSearcher indexSearcher = getIndexSearcher();
//查询文件名以"小"开头的索引 前缀匹配查询
Query query=new PrefixQuery(new Term("fileContent","小"));
System.out.println(query);
printResult(indexSearcher,query,10);
//关闭reader
indexSearcher.getIndexReader().close();
}
短语匹配查询:
/**
* PhraseQuery,是指通过短语来检索,比如我想查“集合 类型”这个短语,
* 那么如果待匹配的document的指定项里包含了"集合 类型"这个短语,
* 这个document就算匹配成功。可如果待匹配的句子里包含的是“集合 中 不可以 存储 基本 数据”,
* 那么就无法匹配,可以设定slop,匹配间隔
* 先给出slop的概念:slop是指两个项的位置之间允许的最大间隔距离
*/
@Test
public void testPhraseQuery() throws Exception{
IndexSearcher indexSearcher = getIndexSearcher();
Builder build = new PhraseQuery.Builder();
build.add(new Term("fileContent","集合"));
build.add(new Term("fileContent","类型"));
//设置slop,即最大相隔多远,即多少个文字的距离,
build.setSlop(8);//表示如果这两个词语相隔20个字以下的位置就匹配
PhraseQuery phraseQuery = build.build();
printResult(indexSearcher,phraseQuery,10);
//关闭reader
indexSearcher.getIndexReader().close();
}
查询结果为:
<b><font color='red'>集合</font></b>中不可以存储基本数据<b><font color='red'>类型</font></b>值。
<b><font color='red'>集合</font></b>容器因为内部的数据结构不同,有多种具体容器。
不断的向上抽取,就形成了集合框架。
2.7.4.5 模糊查询及通配符
/**
* @Description: 测试 FuzzyQuery 模糊查询
* @param: @throws Exception
* @return: void
* @throws
*/
@Test
public void testFuzzyQuery() throws Exception{
IndexSearcher indexSearcher = getIndexSearcher();
//FuzzyQuery是一种模糊查询,它可以简单地识别两个相近的词语
Query query = new FuzzyQuery(new Term("fileContent","网易"));
printResult(indexSearcher,query,10);
//关闭reader
indexSearcher.getIndexReader().close();
}
/**
* @Description: 测试 WildcardQuery 通配符查询
* @param: @throws Exception
* @return: void
* @throws
*/
@Test
public void testWildcardQuery() throws Exception{
IndexSearcher indexSearcher = getIndexSearcher();
//Lucene也提供了通配符的查询,这就是WildcardQuery。
// 通配符“?”代表1个字符,而“*”则代表0至多个字符,与正则表达式相同。
Query query = new WildcardQuery(new Term("fileContent","?时候")); //名字以“时候”结尾
Query query1 = new WildcardQuery(new Term("fileContent","大*")); //名字以“大”开头
printResult(indexSearcher,query,10);
printResult(indexSearcher,query1,10);
//关闭reader
indexSearcher.getIndexReader().close();
}
查询结果为:
以时候结尾:
我们背负着过去的东西前行,也许<b><font color='red'>有时候</font></b>这些东西已经太过沉重。假使再给我们一次机会
我们会怎么做呢,我们能勇敢说出<b><font color='red'>那时候</font></b>没敢说出的话吗?爱要及时,不要吝惜。
以大开头:
内部维护了一个<b><font color='red'>大型</font></b>的byte数组
啊,<b><font color='red'>大海</font></b>啊,你全是水!
2.7.5 条件解析查询
一下分别列出四种条件解析查询方式:
- 查询内容包含集合 || 大海 || 时候的文件
- 指定域查询文件名称包含"网易"的
- 匹配内容以 小 开头的文件
- 匹配文件内容包含"集合" 和 文件名称包含"网易"的文件
可以看出条件解析查询更加灵活和方便,基本能满足之前所有的查询方式。
/**
* @Description: QueryParser 解析表达式查询
* @param: @throws Exception
* @return: void
* @throws
*/
@Test
public void testQueryParser() throws Exception{
/**
* 解析查询表达式
* QueryParser实际上就是一个解析用户输入的工具,可以通过扫描用户输入的字符串,生成Query对象
*/
IndexSearcher indexSearcher = getIndexSearcher();
Query query = new TermQuery(new Term("fileContent","集合"));
// 参数: 默认域 分词解析器
QueryParser queryParser = new QueryParser("fileContent", new IKAnalyzer());
//解析 ,如果不指定域,使用默认域 使用语法书写
Query parse1 = queryParser.parse("集合 大海 时候");//查询内容包含集合 || 大海 || 时候的文件
Query parse2 = queryParser.parse("fileName:网易");//指定域查询文件名称包含"网易"的
Query parse3 = queryParser.parse("fileContent:小*");//匹配内容以 小 开头的文件
Query parse4 = queryParser.parse("fileContent:集合 fileName:网易");//匹配文件内容包含"集合" 和 文件名称包含"网易"的文件
printResult(indexSearcher,parse3,10);
//关闭reader
indexSearcher.getIndexReader().close();
}
2.7.6 权重查询
权重查询与百度搜索排名差不多,指定权重可以让其排在查询结果的前面。
/**
* @Description: 测试带权重的查询
* @param: @throws Exception
* @return: void
* @throws
*/
@Test
public void testWightQuery() throws Exception{
/**
* 解析查询表达式
* MultiFieldQueryParser支持多默认域
*/
IndexSearcher indexSearcher = getIndexSearcher();
// 指定多默认域数组
String[] arr=new String[]{"fileName","fileContent"};
//搜索时设置权重,权重默认是1, 文件名字符合条件的排序在前面
Map<String,Float> boosts = new HashMap<String,Float>();
boosts.put("fileName", 10.0f);//文件名称权重更高,符合条件的文件名称会排在符合条件的内容前面
boosts.put("fileContent", 5.0f);
MultiFieldQueryParser queryParser = new MultiFieldQueryParser(arr, new IKAnalyzer(),boosts);//指定搜索权重
//解析 ,如果不指定域,使用默认域 使用语法书写
Query parse = queryParser.parse("添加");//查询所有默认域里有集合的文档
printResult(indexSearcher,parse,10);
//关闭reader
indexSearcher.getIndexReader().close();
}
查询结果:(查询结果文件名称符合关键词的权重更高会排在内容符合的文档前面)
高亮文档名:<b><font color='red'>添加</font></b>测试权重查询.txt
高亮文件内容: 显示一个DB:show databases;
1,<b><font color='red'>添加</font></b>。
boolean add(Object obj):
boolean addAll(Collection coll):
2,删除