lucene初探, 是为了后面solr做准备的. 如果跳过lucene, 直接去看solr, 估计有点懵.
由于时间的关系, lucene查询方法也有多个, 所以单独出来.
一. 精确查询
????/** ????* 获取 查找对象 ????* @return ????* @throws Exception ????*/ ???private IndexSearcher getSearcher() throws Exception { ???????//1. 创建一个directory对象, 也就是索引库存放的位置 ???????Directory directory = FSDirectory.open(new File(indexDir)); ???????//2. 创建一个indexReader对象, 需要指定directory ???????IndexReader indexReader = DirectoryReader.open(directory); ???????//3. 创建一个indexSearcher对象, 需要指定indexReader对象 ???????IndexSearcher indexSearcher = new IndexSearcher(indexReader); ???????return indexSearcher; ???} ????/** ????* 输出信息到控制台 ????* @param indexSearcher ????* @param query ????* @throws Exception ????*/ ???public void sout(IndexSearcher indexSearcher, Query query) throws Exception { ???????//5. 执行查询 ???????TopDocs topDocs = indexSearcher.search(query, 5); ???????//6. 返回查询结果 ???????ScoreDoc[] scoreDocs = topDocs.scoreDocs; ???????for (ScoreDoc scoreDoc : scoreDocs) { ???????????//获取文档id ???????????int doc = scoreDoc.doc; ???????????//根据文档id获取文档 ???????????Document document = indexSearcher.doc(doc); ???????????//文件名字 ???????????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); ???????????System.out.println("fileSize : " + fileSize); ???????????System.out.println("filePath : " + filePath); ???????????System.out.println("fileContent : " + fileContent); ???????????System.out.println("-----------------------"); ???????} ???} ????/** ????* 精确查询 ????* ????* @throws Exception ????*/ ???@Test ???public void searchIndex() throws Exception { ???????//1. 获取查询对象 ???????IndexSearcher indexSearcher = getSearcher(); ???????//2. 创建一个TermQuery对象, 指定查询的域和查询的关键词 ???????Query query = new TermQuery(new Term("fileName", "生活")); ???????sout(indexSearcher, query); ???????//3. 关闭IndexReader 对象 ???????indexSearcher.getIndexReader().close(); ???}
在查询的时候, 新建一个Term对象, 进去精确匹配. 前一篇提到过, 经过分词器分下来的每一个词或者一段话, 就是一个Term.
这里在新建Term的时候, 传入的是 域名 和 要搜索的词.
这里, 一个Term对象, 只有一个域, 那如果我想查询多个域怎么办呢.
二. 组合查询
/** * 组合查询 */@Testpublic void queryBoolean() throws Exception { ???IndexSearcher searcher = getSearcher(); ???BooleanQuery query = new BooleanQuery(); ???Query query1 = new TermQuery(new Term("fileName", "生活")); ???Query query2 = new TermQuery(new Term("fileContent", "生活")); ???query.add(query1, BooleanClause.Occur.MUST); ???query.add(query2, BooleanClause.Occur.SHOULD); ???//System.out.println(query); ???sout(searcher, query); ???searcher.getIndexReader().close();}
这里的Occur枚举值, 有三个, must, should, must_not .
must : 相当于sql里面的 and 连接
should : 相当于 or , 可有可没有
must_not : 相当于 != , 不包含
这里如果打印query, 会显示: +fileName:生活 fileContent:生活
这是lucene的一种语法, lucene可以根据语法来查询数据. 后面会提到. 如果是must_not , 则使用减号.
如: 将上面的query2使用 MUST_NOT 连接, 则显示成: +fileName:生活 -fileContent:生活
三 . 查询所有
一般查询数据库的时候, 都会提供一个 getAll 方法, 用于查询满足条件的所有数据, 当不传条件时, 就查询所有
lucene也提供了一个查询所有的方法 : MatchAllDocsQuery
/** * 查询所有 * * @throws Exception */@Testpublic void queryAll() throws Exception { ???IndexSearcher searcher = getSearcher(); ???Query query = new MatchAllDocsQuery(); ???sout(searcher, query); ???searcher.getIndexReader().close();}
四. 数值区间查询
/** * 数值区间查询 * * @throws Exception */@Testpublic void queryNumericRange() throws Exception { ???IndexSearcher searcher = getSearcher(); ???Query query = NumericRangeQuery.newLongRange("fileSize", 10L, 647L, true, true); ???sout(searcher, query); ???searcher.getIndexReader().close();}
这里的语法输出就是 : fileSize:[40 to 647]
这是因为我后面两个都设置为true, 表示包含关系. 如果都设置为false, 就是 {40 to 647}
五. 分词器解析查询
如前面提到的, 我输入一句话查询, 结果展示的结果却并不是按照我输入的全匹配结果.
那是因为在查询之前, 对输入的信息, 进行了分词器解析, 然后根据解析结果, 再去查询数据.
/** * 条件解析对象查询 * * @throws Exception */@Testpublic void queryParser() throws Exception { ???IndexSearcher searcher = getSearcher(); ???QueryParser queryParser = new QueryParser("fileName", new IKAnalyzer()); ???//Query query = queryParser.parse("*:*"); ???Query query = queryParser.parse("fileName:这花好漂亮"); ???//Query query = queryParser.parse("花"); ???sout(searcher, query); ???searcher.getIndexReader().close();}
*:* 表示查询所有. 不管是哪个域.
fileName:这花好漂亮 : 表示在fileName域中, 将 "这花好漂亮" 分词解析后, 进行查询
花 : 在fileName域中, 查询花. 因为在QueryParse创建的时候, 指定了域为 fileName
即使我在QueryParser里面指定了要查询的域, 但是在parse的时候, 我可以重新指定域.
这里需要注意的是, 在上面数值区间查询的时候, 如果我直接写语法进去查询, 是查不出来的. 因为数值类型变了. 通过语法输进去, 变成字符串类型了.
从结果中可以看到, 我输入 这花好漂亮, 查出来的却是 军中绿花. 这就是分词的作用了.
六. 多域分词查询
/** * 条件解析对象查询 * * @throws Exception */@Testpublic void queryMultiParser() throws Exception { ???IndexSearcher searcher = getSearcher(); ???String[] fields = {"fileName", "fileContent"}; ???MultiFieldQueryParser queryParser = new MultiFieldQueryParser(fields, new IKAnalyzer()); ???Query query = queryParser.parse("生活大爆炸"); ???sout(searcher, query); ???searcher.getIndexReader().close();}
多域分词查询, 没啥好说的了.
lucene 初探 - 查询
原文地址:https://www.cnblogs.com/dudadi/p/8127685.html