Lucene——搜索和相关度排序
Posted 雪山上的蒲公英
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lucene——搜索和相关度排序相关的知识,希望对你有一定的参考价值。
1. 搜索
1.1 创建查询对象的方式
- 通过Query子类来创建查询对象
Query子类常用的有:TermQuery、NumericRangeQuery、BooleanQuery
特点:不能输入lucene的查询语法,不需要指定分词器
- 通过QueryParser来创建查询对象(常用)
QueryParser、MultiFieldQueryParser
特点:可以输入lucene的查询语法、可以指定分词器
1.2 通过Query子类来创建查询对象
1.2.1 TermQuery(精确的词项查询)
@Test public void termQuery() { // 创建TermQuery对象 Query query = new TermQuery(new Term("description", "java")); doSearch(query); }
@Test private void doSearch(Query query) { // 创建IndexSearcher // 指定索引库的地址 try { File indexFile = new File("D:\\DBIndex\\"); Directory directory = FSDirectory.open(indexFile); IndexReader reader = DirectoryReader.open(directory); IndexSearcher searcher = new IndexSearcher(reader); // 通过searcher来搜索索引库 // 第二个参数:指定需要显示的顶部记录的N条 TopDocs topDocs = searcher.search(query, 10); // 根据查询条件匹配出的记录总数 int count = topDocs.totalHits; System.out.println("匹配出的记录总数:" + count); // 根据查询条件匹配出的记录 ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs) { // 获取文档的ID int docId = scoreDoc.doc; // 通过ID获取文档 Document doc = searcher.doc(docId); System.out.println("商品ID:" + doc.get("id")); System.out.println("商品名称:" + doc.get("name")); System.out.println("商品价格:" + doc.get("price")); System.out.println("商品图片地址:" + doc.get("pic")); System.out.println("=========================="); // System.out.println("商品描述:" + doc.get("description")); } // 关闭资源 reader.close(); } catch (IOException e) { e.printStackTrace(); } }
1.2.2 NumericRangeQuery(数字范围查询)
@Test public void numericRangeQuery() { // 创建NumericRangeQuery对象 // 参数:域的名称、最小值、最大值、是否包含最小值、是否包含最大值 Query query = NumericRangeQuery.newFloatRange("price", 55f, 60f, true, false); doSearch(query); }
1.2.3 BooleanQuery(组合查询)
@Test public void booleanQuery() { // 创建BooleanQuery BooleanQuery query = new BooleanQuery(); // 创建TermQuery对象 Query q1 = new TermQuery(new Term("description", "lucene")); // 创建NumericRangeQuery对象 // 参数:域的名称、最小值、最大值、是否包含最小值、是否包含最大值 Query q2 = NumericRangeQuery.newFloatRange("price", 55f, 60f, true, false); // 组合关系代表的意思如下: // 1、MUST和MUST表示“与”的关系,即“交集”。 // 2、MUST和MUST_NOT前者包含后者不包含。 // 3、MUST_NOT和MUST_NOT没意义 // 4、SHOULD与MUST表示MUST,SHOULD失去意义; // 5、SHOUlD与MUST_NOT相当于MUST与MUST_NOT。 // 6、SHOULD与SHOULD表示“或”的概念。 query.add(q1, Occur.MUST_NOT); query.add(q2, Occur.MUST_NOT); doSearch(query); }
1.3 通过QueryParser来创建查询对象
1.3.1 QueryParser
通过QueryParser来创建query对象,可以指定分词器,搜索时的分词器和创建该索引的分词器一定要一致。还可以输入查询语句。
@Test public void indexSearch() throws Exception { // 创建query对象 // 使用QueryParser搜索时,需要指定分词器,搜索时的分词器要和索引时的分词器一致 // 第一个参数:默认搜索的域的名称 QueryParser parser = new QueryParser("description", new StandardAnalyzer()); // 通过queryparser来创建query对象 // 参数:输入的lucene的查询语句(关键字一定要大写) Query query = parser.parse("description:java AND lucene"); doSearch(query); }
1.3.2 MultiFieldQueryParser(多域查询)
@Test public void multiFieldQueryParser() throws Exception { // 创建 MultiFieldQueryParser // 默认搜索的多个域的域名 String[] fields = { "name", "description" }; Analyzer analyzer = new StandardAnalyzer(); Map<String, Float> boosts = new HashMap<String, Float>(); boosts.put("name", 200f); MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer, boosts); // Query query = parser.parse("name:lucene OR description:lucene"); Query query = parser.parse("java"); System.out.println(query); doSearch(query); }
1.3.3 查询语法
(1)基础的查询语法,关键词查询
域名+“:”+搜索的关键字
例如:content:java
(2)范围查询
域名+“:”+[最小值 TO 最大值]
例如:size:[1 TO 1000]
注意:QueryParser不支持对数字范围的搜索,它支持字符串范围。数字范围搜索建议使用NumericRangeQuery。
(3)组合条件查询
Occur.MUST 查询条件必须满足,相当于and |
+(加号) |
Occur.SHOULD 查询条件可选,相当于or |
空(不用符号) |
Occur.MUST_NOT 查询条件不能满足,相当于not非 |
-(减号) |
(3.1)+条件1 +条件2:两个条件之间是并且的关系and
例如:+filename:apache +content:apache
(3.2)+条件1 条件2:必须满足第一个条件,忽略第二个条件
例如:+filename:apache content:apache
(3.3)条件1 条件2:两个条件满足其一即可。
例如:filename:apache content:apache
(3.4)-条件1 条件2:必须不满足条件1,要满足条件2
例如:-filename:apache content:apache
(4)组合查询(3)的第二种写法
- 条件1 AND 条件2
- 条件1 OR 条件2
- 条件1 NOT 条件2
1.4 TopDocs
Lucene搜索结果可通过TopDocs遍历,TopDocs类提供了少量的属性,如下:
方法或属性 |
说明 |
totalHits |
匹配搜索条件的总记录数 |
scoreDocs |
顶部匹配记录 |
注意:
Search方法需要指定匹配记录数量n:indexSearcher.search(query, n)
TopDocs.totalHits:是匹配索引库中所有记录的数量
TopDocs.scoreDocs:匹配相关度高的前边记录数组,scoreDocs的长度小于等于search方法指定的参数n
2. 相关度排序
2.1 什么是相关度排序
相关度排序就是查询关键字与查询结果的匹配相关度。匹配越高的越靠前。Lucene是通过打分来进行相关度排序的。
2.1.1 打分分两步:
step1:根据词计算词的权重
step2:根据词的权重进行打分
2.1.2 词的权重
词指的就是term。也就是说一个term对一个文档的重要性,就叫词的权重。
影响词的权重的方式有两种:
- Tf ——词在同一个文档中出现的频率
Tf越高,说明词的权重越高
- Df ——词在多个文档中出现的频率
Df越高,说明词的权重越低
以上是自然打分的规则。
2.2 设置boost值影响打分
Boost:加权值,默认是1.0f。
设置加权值可以在创建索引时(如下代码)设置,也可以在查询时(见1.3.2 MultiFieldQueryParser(多域查询))设置。
for (Book book : list) { document = new Document(); // store:如果是yes,则说明存储到文档域中 // 图书ID // 不分词、索引、存储 StringField Field id = new StringField("id", book.getId().toString(), Store.YES); // 图书名称 // 分词、索引、存储 TextField Field name = new TextField("name", book.getName(), Store.YES); ············
// 设置boost值 if (book.getId() == 4) description.setBoost(100f); // 将field域设置到Document对象中 document.add(id); ············· }
Boost值是设置到Field域上的。
以上是关于Lucene——搜索和相关度排序的主要内容,如果未能解决你的问题,请参考以下文章