`
kernaling.wong
  • 浏览: 78874 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类

我在工作中的Lucene中关于 MUST , SHOULD的一个想法

    博客分类:
  • java
阅读更多
开场白:
我看过几本书说关于lucene中的BooleanQuery查询条件的参数

Boolean.Clause.MUST,Boolean.Clause.MUST_NOT,Boolean.Clause.SHOULD之关的关系,其实就好象是集合中的交集并集等关系.这里不重复书的例子,说一点我平时在工作中的应用吧.
   书基本都是说,当MUST与SHOULD关联使用的时候,跟MUST使用是一样的,那天我做一个关系搜索结果按相关排序,这里简单说一下需求,这是说用户输入关键字后,应该把所有的付费会员商品按相关度从高到低排序来推荐给用户.现在已经一批付费会员的编号了,同时知道会员用户的产品名称与产品介绍。那应该如何去按照输入的关键字来排序呢?要知道,关键字有可能与付费会员的产品完全不相关,当然,这些不相关产品会排在最后边。


现在贴出相关的代码

package com.lucene.test;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopFieldDocs;

/**
 * 
 * @author kernaling.wong
 *	本类只是演示should对结果的出现是没有影响的,但是影响结果的相关度,可以利用之来进度某些相关的排序搜索
 */
public class LuceneTest {
	private static String INDEX_PATH = "./Index/";
	public static void main(String[] args) {

		if(false){					//做索引的时候就把 true;
			IndexWriter writer = null;
			try{
				writer = new IndexWriter(INDEX_PATH,new StandardAnalyzer(),MaxFieldLength.LIMITED);
				
				Document doc = new Document();
				Field fieldCode = new Field("Code","1",Field.Store.YES,Field.Index.ANALYZED);
				Field fieldName = new Field("Name","电热炉",Field.Store.YES,Field.Index.ANALYZED);
				Field fieldInfo = new Field("Info","这是一个电热

炉",Field.Store.YES,Field.Index.ANALYZED);
				doc.add(fieldCode);
				doc.add(fieldName);
				doc.add(fieldInfo);
				writer.addDocument(doc);
				
				doc = new Document();
				fieldCode = new Field("Code","2",Field.Store.YES,Field.Index.ANALYZED);
				fieldName = new Field("Name","电水壶",Field.Store.YES,Field.Index.ANALYZED);
				fieldInfo = new Field("Info","解放牌电水壶",Field.Store.YES,Field.Index.ANALYZED);
				doc.add(fieldCode);
				doc.add(fieldName);
				doc.add(fieldInfo);
				writer.addDocument(doc);
				
				doc = new Document();
				fieldCode = new Field("Code","3",Field.Store.YES,Field.Index.ANALYZED);
				fieldName = new Field("Name","水杯",Field.Store.YES,Field.Index.ANALYZED);
				fieldInfo = new Field("Info","钢化水杯",Field.Store.YES,Field.Index.ANALYZED);
				doc.add(fieldCode);
				doc.add(fieldName);
				doc.add(fieldInfo);
				writer.addDocument(doc);
				
				doc = new Document();
				fieldCode = new Field("Code","4",Field.Store.YES,Field.Index.ANALYZED);
				fieldName = new Field("Name","碟子",Field.Store.YES,Field.Index.ANALYZED);
				fieldInfo = new Field("Info","质量很好",Field.Store.YES,Field.Index.ANALYZED);
				doc.add(fieldCode);
				doc.add(fieldName);
				doc.add(fieldInfo);
				writer.addDocument(doc);
				
				System.out.println("索引建立完成!");
			}catch(Exception ex){
				ex.printStackTrace();
			}finally{
				if(writer != null){
					try{
						writer.close();
					}catch(Exception ex){
						ex.printStackTrace();
					}
				}
			}
		}else{
			
			IndexSearcher search = null;
			IndexReader ir = null;
			try{
				search = new IndexSearcher(INDEX_PATH);
				
				String keyword = "水";		//用户输入了需要搜索的关键字
				
				BooleanQuery bq = new BooleanQuery();
				
				/**
				 * 以下上查询条件,因为无论用户输入的关键字如何都需要全部显示付费会员商品,相关度从高

到低
				 */
				BooleanQuery tmpBQ = new BooleanQuery();			//这是一个
				tmpBQ.add(new TermQuery((new Term("Code","1"))),BooleanClause.Occur.MUST);
				tmpBQ.add(new TermQuery((new Term("Name",keyword))),BooleanClause.Occur.SHOULD);
				tmpBQ.add(new TermQuery((new Term("Info",keyword))),BooleanClause.Occur.SHOULD);
				bq.add(tmpBQ,BooleanClause.Occur.SHOULD);
				
				tmpBQ = new BooleanQuery();
				tmpBQ.add(new TermQuery((new Term("Code","2"))),BooleanClause.Occur.MUST);
				tmpBQ.add(new TermQuery((new Term("Name",keyword))),BooleanClause.Occur.SHOULD);
				tmpBQ.add(new TermQuery((new Term("Info",keyword))),BooleanClause.Occur.SHOULD);
				bq.add(tmpBQ,BooleanClause.Occur.SHOULD);
				
				tmpBQ = new BooleanQuery();
				tmpBQ.add(new TermQuery((new Term("Code","3"))),BooleanClause.Occur.MUST);
				tmpBQ.add(new TermQuery((new Term("Name",keyword))),BooleanClause.Occur.SHOULD);
				tmpBQ.add(new TermQuery((new Term("Info",keyword))),BooleanClause.Occur.SHOULD);
				bq.add(tmpBQ,BooleanClause.Occur.SHOULD);
				
				tmpBQ = new BooleanQuery();
				tmpBQ.add(new TermQuery((new Term("Code","4"))),BooleanClause.Occur.MUST);
				tmpBQ.add(new TermQuery((new Term("Name",keyword))),BooleanClause.Occur.SHOULD);
				tmpBQ.add(new TermQuery((new Term("Info",keyword))),BooleanClause.Occur.SHOULD);
				bq.add(tmpBQ,BooleanClause.Occur.SHOULD);
				
				
				
				Sort sort = new Sort(SortField.FIELD_SCORE);		//按相关度来排序
				TopFieldDocs tdocs = search.search(bq,null,4,sort);
				
				ScoreDoc scoreDocs[] = tdocs.scoreDocs;
				ir = search.getIndexReader();
				for(int i=0;i<scoreDocs.length;i++){
					Document tmpDoc = ir.document(scoreDocs[i].doc);
					System.out.println("文档得分:"+scoreDocs[i].score+"\t产品编号:"+tmpDoc.get

("Code")+"\t产品名称:"+tmpDoc.get("Name")+"\t产品说明:"+tmpDoc.get("Info"));
				}
				
			}catch(Exception ex){
				ex.printStackTrace();
			}finally{
				try{
					if(search != null){
						search.close();
					}
					
					if(ir != null){
						ir.close();
					}
				}catch(Exception ex){
					ex.printStackTrace();
				}
				
			}
		}
		
		
	}
}


测试环境是  windowsXP + jdk1.6 与 lucene2.4.
实现后排序的结果应该是这样


后记
    以上那种方面需要说明的是,如果出现了大量的付费会员的时候,即,需要BooleanClause.Occur.SHOULD很多用户编号的时候,建议不要再用些方法了,同时BooleanQuery条件中会限制BooleanQuery.add的条件数量,默认是1024个,当然也可以手动设置它的最大上限,通过setMaxClauseCount(int maxCount),因为按我以上那种方法,当注册用户数很多,比如10W或者以上的时候,搜索时性能就会成为瓶颈了。这个时候,我现在想出的方法就是更改Lucene索引的字段,不要再指定付费用户去SHOULD每一个付费用户了,改为增加一个字段去表示是否注册用户.然后再用上边类似方法就可以比较高效率地实现这个功能了,最原先那个种方法是头脑发热的时候想出来的,那时付费的用户并不多,所以就算这样实现起来都没有问题,不过现在也已经改为到第二种方法了,在暂时无法改变lucene源代码实现与算法的时候,那只能改变自己的方法了.
  • 大小: 37.8 KB
1
1
分享到:
评论
4 楼 kernaling.wong 2015-05-18  
whz137458 写道
我觉得你思路有问题!(A&&B||C)||(D&&B||C)||(E&&B||C)
你就没想过(A||D||E)&&(B||C)

望指教~~
刚才我认真看了您的回复,其实呢,我那里的重点不在于哪个"或"哪个条件,我那里是测试例子,本来是通过一个 for 循环去拼成  (A&&B||C)||(D&&B||C)||(E&&B||C) 这样的条件,但后来为了测试例子方便才直接写了三个这样子的条件了.
当然您说的也有道理.
3 楼 whz137458 2015-04-09  
我觉得你思路有问题!(A&&(B||C))||(D&&(B||C))||(E&&(B||C))
你就没想过(A||D||E)&&(B||C)
2 楼 whz137458 2015-04-09  
我觉得你思路有问题!(A&&B||C)||(D&&B||C)||(E&&B||C)
你就没想过(A||D||E)&&(B||C)
1 楼 cf2huihui 2013-03-06  
谢谢,帮助很大

相关推荐

    lucene,lucene教程,lucene讲解

    第一个是 FSDirectory,它表示一个存储在文件系统中的索引的位置。 第二个是 RAMDirectory,它表示一个存储在内存当中的索引的位置。 public void add(Query query, BooleanClause.Occur occur) BooleanClause...

    lucene创建修改删除组合条件查询

    例如,可以创建两个`Query`对象,一个用于匹配关键词,另一个用于时间范围,然后通过`BooleanClause.Occur`设置操作符(如SHOULD、MUST或MUST_NOT),将它们组合成一个布尔查询。 **类似MySQL的LIKE条件**在Lucene...

    Lucene4.X实战类baidu搜索的大型文档海量搜索系统-07.Lucene搜索实战1 共4页.pptx

    如果一个子句是MUST,另一个是MUST_NOT,则结果中不会包含MUST_NOT子句对应的文档。SHOULD子句则代表可选条件,多个SHOULD子句之间是逻辑或的关系,它们的组合结果是所有子句的并集。在实际编程中,这些概念可以通过...

    Lucene查询语法

    示例代码展示了如何构建两个关键词`word1`和`word2`至少出现在`name`字段或`body`字段中的一个查询。 ```java TermQuery query1 = new TermQuery(new Term("name", "word1")); TermQuery query2 = new TermQuery(new...

    lucene个人总结

    在创建索引之前,首先需要创建一个 `IndexWriter` 对象。这一步骤涉及到目录(Directory)的选择以及分词器(Analyzer)的设置: - **选择目录**:通过 `FSDirectory.open(new File(indexPath));` 指定索引存储的...

    Lucene2.4入门总结

    Lucene 是一个高性能、全文本搜索库,由 Apache 软件基金会开发。它提供了高级文本检索功能,广泛用于构建搜索引擎和其他需要高效全文检索能力的应用。本文将重点介绍 Lucene 2.4 版本的基本概念和使用方法,帮助...

    Luence和ElasticSearch面试准备.docx

    Lucene是一个高性能、全文本搜索库,而Elasticsearch则是在Lucene的基础上构建的一个分布式、RESTful风格的搜索和数据分析引擎。两者在面试中常常被提及,以下是对这两个技术的关键知识点的深入解析。 首先,Lucene...

    lucene-搜索过程源码解析-Score树

    Lucene是一个开源的全文检索引擎工具包,它提供了创建索引、执行高效搜索以及排序结果的能力。在Lucene中,Score树是用于计算文档相关性得分的关键结构,从而决定搜索结果的排序。 ### 一、`IndexSearcher.search...

    JAVA使用ElasticSearch查询in和not in的实现方式

    Elasticsearch是一个基于Lucene的搜索服务器,提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。它是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于...

    使用Lucene实现一个简单的布尔搜索功能

    Apache Lucene 是一个高度可扩展的全文检索库,它为开发者提供了一套强大的搜索引擎功能,以便在各种应用程序中实现复杂的全文搜索。Lucene 不是一个独立的搜索引擎产品,而是需要开发者将其集成到自己的系统中,以...

    lucence.net查询

    例如,`new BooleanQuery.Builder().Add(query1, Occur.MUST).Add(query2, Occur.SHOULD).Build()`将创建一个必须包含query1且可以包含query2的查询。 2. **短语查询**:通过`PhraseQuery`,可以查找精确的短语匹配...

    分布式搜索elasticsearchjavaAPI之(五)------搜索.pdf

    在上面的代码中,我们使用 BoolQuery 构建了一个复杂的搜索条件,包括 must、mustNot、should 方法。 FilteredQuery FilteredQuery 是一种特殊的搜索方式,允许开发者使用过滤条件来限制搜索结果。例如,以下代码...

    lucene-fluent-query-builder:围绕构建 Lucene.Net 查询的便捷 Fluent-API

    安装PM &gt; Install-Package LrNet.Lucene.Fluent 首先,在使用查询构建器之前,您需要在项目中的某处指定: QueryBuilder . Version = /* Lucene Version you want to use */QueryBuilder . DefaultAnalyzer = /* ...

    深入解析:如何在 Elasticsearch 中执行布尔查询

    例如,查询只需要满足“标题包含 Elasticsearch”或者“作者不是 John Doe”中的任意一个条件即可。 3. **NOT**:表示指定的子查询必须排除在外。例如,查询结果中不能出现“作者是 John Doe”的记录。 4. **FILTER*...

    Laravel开发-elsquerybuildertrait

    在Laravel框架中,Elasticsearch(简称ES)是一个常用的数据搜索引擎,特别是在处理大量数据时,它的性能和灵活性使得开发者倾向于使用它替代传统的数据库。`ELSQueryBuilderTrait`是为简化在Laravel应用中与Elastic...

    ElasticSearch可扩展的开源弹性搜索解决方案.docx

    - **节点和集群**:ElasticSearch 支持在多台服务器上部署,形成一个集群。每个服务器上的 ElasticSearch 实例称为一个节点。 - **分片(Shard)**:当单个节点的计算能力和硬件限制不足以应对大量数据时,可以将...

    分布式搜索elasticsearchjavaAPI之(五)------搜索实用.pdf

    Elasticsearch是一个强大的分布式搜索引擎,基于Lucene库构建。在Java API中,与Elasticsearch交互,特别是进行搜索操作,主要是通过使用`QueryBuilder`对象来构造JSON格式的查询条件。本篇文章将深入探讨如何利用...

    资源前后端分离式分布式微服务架构项目搜索服务讲义+源码+视频

    集群中有一个主节点负责协调集群状态和其他节点的工作负载分配。 2. **创建集群**: 首先安装 Elasticsearch,然后配置集群名称、网络设置等,启动多个节点并使其加入同一个集群。 3. **查询集群健康**: 使用 `_...

    G04-杨樾人-基于Elasticsearch集群的数据查询优化1

    这样可以确保在任意一个节点故障时,数据仍能被其他节点接管,保持服务的连续性。 **三、Elasticsearch的查询参数优化** 1. **Lucene的打分模型** Elasticsearch基于Lucene的TF-IDF评分模型来决定搜索结果的...

Global site tag (gtag.js) - Google Analytics