lucene多条件查询怎么获取查询结果

2151人阅读
Lucene(4)
Lucene在结果中查询的机制及在我们项目中的应用
当一次检索完毕后,希望能从上一次检索的结果集合中进行二次查询,以一步步缩小搜索结果结合,比便能够更好地对信息进行筛选。
这种筛选过程,其行为与Filter所要完成的工作非常类似,都是过滤掉一部分文档,只留下另一部分文档。因此,Lucene提供了内置的QueryFilter来帮助完成这种功能。
我们来看一下QueryFilter的源代码:
public class QueryFilter extends CachingWrapperFilter {
& /** Constructs a filter which only matches documents matching
&& * &code&query&/code&.
& public QueryFilter(Query query) {
&&& super(new QueryWrapperFilter(query));
& public boolean equals(Object o) {
&&& return super.equals((QueryFilter)o);
& public int hashCode() {
&&& return super.hashCode() ^ 0x923F64B9;&
可以发现QueryFilter继承了CachingWrapperFilter,而CachingWrapperFilter又继承了Filter。
再看下QueryFilter的构造方法
public QueryFilter(Query query) {
&&& super(new QueryWrapperFilter(query));
new了一个QueryWrapperFilter对象,而QueryWrapperFilter继承了Filter,所以QueryFilter本质是个过滤器Filter,对搜索进行二次检索。
下面我们来开下QueryFilter的用法:
//首先构造一个RangeQuery,查找某一时间段内出版的所有文档
Term begin = new Term(&Publishdate&,&&);
Term end = new Term(&publishdate&,&&);
RangeQuery q = new
RangeQuery(begin,end,true);
//实例化一个QueryFilter,将RangeQuery赋给它
QueryFilter filter = new QueryFilter(q);
//构造一个TermQuery,查询所有securitylevel为NORMAL的文档
Term normal = new Term(&securitylevel&,SECURITY_NORMAL+&&);
TermQuery query = new TermQuery(normal);
//使用上面构造的QueryFilter来进行检索,也就是说,在RangeQuery的基础上,在进行
//TermQuery
IndexSearcher searcher = new
IndexSearcher(INDEX_STORE_PATH);
Hits hits = searcher.search(query,filter);
上面的代码就是在第一次RangeQuery查找的结果结合中,进行TermQuery,即在到发行的文档中查找所有安全级别为NORMAL的文档。
因此Lucene在结果中查询的机制就是过滤器查询。
由于我们的项目是从手机客户端向服务器端发送URL查询,所有的信息均在URL中,因此是一种无状态的查询,所以我们每次查询需要汇总URL中的查询信息再进行一次查询。而我们已经实现的过滤器查询其实也就是一种在结果中查询机制的实现,而且我们加入了Lucene的缓存机制,将会使我们的查询速度大大提高。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:237921次
积分:3212
积分:3212
排名:第6360名
原创:85篇
转载:96篇
评论:48条
(1)(2)(1)(3)(6)(8)(6)(1)(11)(18)(4)(10)(5)(5)(2)(2)(2)(1)(2)(1)(2)(1)(3)(1)(3)(3)(6)(2)(1)(1)(1)(2)(6)(14)(2)(7)(2)(9)(10)(2)(6)(7)2326人阅读
java(17)
lucene(3)
几个查询用法如下代码:
数字范围查询:索引时字段保存为
new NumericField(name,& Field.Store.YES(NO), true(false).setIntValue( num );
Query numericRangeQuery = NumericRangeQuery.newIntRange(&size&, 20, 150, true, true);
时间范围查询,其实就是数字范围查询, 因为都知道Date是根据一个long 型变量构造出来的
所以用法同上, 只不过需要对传入的日期格式转换成long
文件的内容:
name: java
content: 全国软件专业人才设计与开发大赛
帽子和服装
Lucene实战(第二版) Lucene in action
人民邮电出版社
the quick brown fox jumped over the lazy dog
public class QueryTest {
public void testTermQuery() throws Exception {
// Term t = new Term(&content&, &服装&);
Term term = new Term(&size&, &53&);
TermQuery termQuery = new TermQuery(term);
doSearch(termQuery);
public void testRangeQuery() throws Exception {
// 通过范围查找, 这里比较的是字符串, 所以实际 20 比 150 大 , 即找不到结果
// Query termRangeQuery = new TermRangeQuery(&size&, &020&, &150&, true, true);
//虽然可以通过给20 补0 (即 020)实现20和150的比较, 不过太麻烦, 而且不同的情况补0也不同
//Lucene 提供了NumberTools.longToString(num), 已过时
//查看api, NumberTools类已被NumericUtils代替
//修改如下还是出不来想要的结果,
// Query termRangeQuery = new TermRangeQuery(&size&, NumericUtils.longToPrefixCoded(20L), NumericUtils.longToPrefixCoded(150L), true, true);
//结果new了半天都没new出来, 继续查api:
//You create a new NumericRangeQuery with the static factory methods, eg:
//Query q = NumericRangeQuery.newFloatRange(&weight&, 0.03f, 0.10f, true, true);
//换了半天总与出来了, 原因是建立索引时:使用的Field, 而使用NumericRangeQuery, 必须使用NumericField:
//A Query that matches numeric values within a specified range. To use this,
//you must first index the numeric values using NumericField (expert: NumericTokenStream).
//If your terms are instead textual, you should use TermRangeQuery.
//NumericRangeFilter is the filter equivalent of this query.
//numericField有别于Field的几点:
//NumericField size = new NumericField(&size&, Field.Store.YES, true);
//size.setLongValue(file.length());
Query numericRangeQuery = NumericRangeQuery.newLongRange(&size&, 20L, 150L, true, true);
doSearch(numericRangeQuery);
public void testPrefixQuery() throws Exception {
//Term term = new Term(&content&, &子&);//如果存在“子”开头的分词, 就符合条件查出来了
Term term = new Term(&name&, &j&);//如果存在“子”开头的分词, 就符合条件查出来了
&PrefixQuery prefixQuery = new PrefixQuery(term);
&doSearch(prefixQuery);
&&&& @Test
public void testBooleanQuery() throws Exception&& &{
//查询时间符合以下min_time到max_time区间段的文件
long min_time = 4L - 1000L;
&long max_time = 4L + 1000L;
Query num_range_query = NumericRangeQuery.newLongRange(&date&, min_time, max_time, true, true);
&//query 2
Query termQuery = new TermQuery(new Term(&name&, &test&));//那么重存在test
&//query 3
Query prefixQuery = new PrefixQuery(new Term(&name&, &j&));
&BooleanQuery booleanQuery = new BooleanQuery();
&booleanQuery.add(num_range_query, BooleanClause.Occur.MUST);//查询结果一定要在以上时间范围区间
&booleanQuery.add(termQuery, BooleanClause.Occur.MUST_NOT);//查询结果不能包含name=test的结果
& &booleanQuery.add(prefixQuery, BooleanClause.Occur.SHOULD);//可选项
&doSearch(booleanQuery);
public void testPhraseQuery() throws Exception {
PhraseQuery phraseQuery = new PhraseQuery();
//为什么就没有add(term) 方法呢?
//因为Query类里面没有此方法
//Query phraseQuery = new PhraseQuery();
String[] strs = {&quick&, &brown&, &jumped&, &lazy&};
//the quick brown fox jumped over the lazy dog
//quick--1-&brown, brown--2-&jumped, jumped--3-&lazy, 所以slop设成3才会有结果搜到
//前面的单词要移动slop次到达后面的单词(相邻的单词), 需要注意的是brown--&jumped和 jumped--&brown需要的slop值不同
//参考《Lucene 实战(第二版)lucene in action》 P92
phraseQuery.setSlop(3);
for(String s: strs){
phraseQuery.add(new Term(&content&, s));
doSearch(phraseQuery);
* 使用通配符查询, 可能会降低系统性能
* @throws Exception
public void testWildcardQuery() throws Exception {
//Term term = new Term(&name&, &ja?a&);//? 匹配单个
Term term = new Term(&content&, &全*大&);//* 匹配所有
Query wildcardQuery = new WildcardQuery(new Term(&name&, &j*a&));
doSearch(wildcardQuery);
* 模糊查询
* @throws Exception
public void testFuzzyQuery() throws Exception {
Term term = new Term(&name&, &jeav&);//通过jeav与实际字段的相似程度查询
Query fuzzyQuery = new FuzzyQuery(term);
doSearch(fuzzyQuery);
private void doSearch(Query query) throws Exception{
Directory dir = FSDirectory.open(new File(&E:/lucene/index&));
IndexReader reader = IndexReader.open(dir);
IndexSearcher searcher = new IndexSearcher(reader);
TopDocs hits = searcher.search(query, 100);
System.out.println(&共找到& + hits.totalHits + &条记录&);
ScoreDoc[] docs = hits.scoreD
for(int i = 0; i & docs. i++){
int docId = docs[i].
Document doc = searcher.doc(docId);
System.out.println(&name: & + doc.get(&name&));
System.out.println(&size: & + doc.get(&size&));
System.out.println(&content: & + doc.get(&content&));
searcher.close();
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:64561次
积分:1041
积分:1041
排名:千里之外
原创:40篇
评论:11条
(1)(3)(9)(6)(5)(2)(2)(2)(1)(10)基于lucene的案例开发:实时索引的检索
在前面的博客中,我们已经介绍了IndexSearcher中的检索方法,也介绍了如何基于lucene中的NRT*类去创建实时索引,在这篇博客中我们就重点介绍下基于实时索引的检索方案。在开始介绍之前,我们首先定一下检索结果的数据结构(这样做的好处是无论是什么检索,得到的数据结构都是一样的,方便以后的处理~)
原来我长这样
检索结果的数据结构主要包括两个字段,如下:
private List
这两个字段分别代表着该检索条件下的符合条件的记录条数和本次查询到的记录数组(该记录是索引中的记录),因此检索结果类源代码如下:
* @Description:
索引搜索结果数据结构
package com.lulei.lucene.index.
import java.util.L
import org.apache.lucene.document.D
public class SearchResultBean {
private List
public int getCount() {
public void setCount(int count) {
this.count =
public List getDatas() {
public void setDatas(List datas) {
this.datas =
检索原来如此简单
检索结果介绍完了,下面就看下如何基于上次博客中的实时索引去检索数据,不知还记得上篇博客中封装的getIndexSearcher()方法(如果忘记了,看下该系列的前一篇博客),这个方法提供了当前最新可用的IndexSearcher对象,索引我们再去检索的时候,直接调用该方法即可。IndexManager类实现了另类的单例模式,使用了索引名来标识IndexManager,因此我们在写检索基类的时候,需要添加一个构造方法,如下:
public NRTSearch(String indexName) {
indexManager = IndexManager.getIndexManager(indexName);
在NRTSearch类中,我们主要封装4个方法:
1.public int getIndexNum(){}
2.public SearchResultBean search(Query query, int start, int end){}
3.public SearchResultBean search(Query query, int start, int end, Sort sort){}
4.public SearchResultBean search(int start, int count){}
在四个方法分别实现:
1.获取索引中的记录条数;
2.根据query查询索引,根据相关读排序,返回[start, end)记录;
3.根据query查询索引,根据指定sort排序,返回[start, end)记录;
4:从索引中的第start条开始,获取后面的count条记录(如果start + count 大于索引中的记录总条数,则从头补齐)。
这四个方法已经可以实现了80%的站内搜索功能,如果还有其他复杂的,可以根据实际情况来拓展,NRTSearch类源代码如下:
* @Description:
索引的查询操作
package com.lulei.lucene.index.
import java.util.ArrayL
import java.util.L
import org.apache.lucene.document.D
import org.apache.lucene.search.IndexS
import org.apache.lucene.search.Q
import org.apache.lucene.search.S
import org.apache.lucene.search.TopD
import com.lulei.lucene.index.manager.IndexM
import com.lulei.lucene.index.model.SearchResultB
public class NRTSearch {
private IndexManager indexM
* @param indexName 索引名
public NRTSearch(String indexName) {
indexManager = IndexManager.getIndexManager(indexName);
* @Author:lulei
* @Description: 索引中的记录数量
public int getIndexNum() {
return indexManager.getIndexNum();
* @param query 查询字符串
* @param start 起始位置
* @param end 结束位置
* @author lulei
* @return 查询结果
public SearchResultBean search(Query query, int start, int end) {
start = start & 0 ? 0 :
end = end & 0 ? 0 :
if (indexManager == null || query == null || start &= end) {
SearchResultBean result = new SearchResultBean();
List datas = new ArrayList();
result.setDatas(datas);
IndexSearcher searcher = indexManager.getIndexSearcher();
TopDocs docs = searcher.search(query, end);
result.setCount(docs.totalHits);
end = end & docs.totalHits ? docs.totalHits :
for (int i = i & i++) {
datas.add(searcher.doc(docs.scoreDocs[i].doc));
} catch (Exception e) {
e.printStackTrace();
} finally {
indexManager.release(searcher);
* @param query 查询字符串
* @param start 起始位置
* @param end 结束位置
* @param sort 排序条件
* @return 查询结果
public SearchResultBean search(Query query, int start, int end, Sort sort) {
start = start & 0 ? 0 :
end = end & 0 ? 0 :
if (indexManager == null || query == null || start &= end) {
SearchResultBean result = new SearchResultBean();
List datas = new ArrayList();
result.setDatas(datas);
IndexSearcher searcher = indexManager.getIndexSearcher();
TopDocs docs = searcher.search(query, end, sort);
result.setCount(docs.totalHits);
end = end & docs.totalHits ? docs.totalHits :
for (int i = i & i++) {
datas.add(searcher.doc(docs.scoreDocs[i].doc));
} catch (Exception e) {
e.printStackTrace();
} finally {
indexManager.release(searcher);
* @param start
* @param count
* @Author:lulei
* @Description: 按序号检索
public SearchResultBean search(int start, int count) {
start = start & 0 ? 0 :
count = count & 0 ? 0 :
if (indexManager == null) {
SearchResultBean result = new SearchResultBean();
List datas = new ArrayList();
result.setDatas(datas);
IndexSearcher searcher = indexManager.getIndexSearcher();
result.setCount(count);
for (int i = 0; i & i++) {
datas.add(searcher.doc((start + i) % getIndexNum()));
} catch (Exception e) {
e.printStackTrace();
} finally {
indexManager.release(searcher);
到这里为止,NRTSearch类就介绍完毕了,之后就可以根据实际的应用来创建子类,实现一系列的查询操作,如:关键字检索、分类检索、标签检索、作者检索等等,在之后的应用中在继续介绍。Lucene如何进行查询_百度知道
Lucene如何进行查询
提问者采纳
BooleanQuery();document&4;=&new&booleanQ=&ScoreDoc[]&nbsp.newIntRange(&=&BooleanQuery&NumericRangeQuery&nbspIndexReader&searcher&NumericRangeQi++)&nbsp,&searcher.O=&10);}lucene &Integer(20);{Document&nbsp,&nbsp.doc).9;//一般系统中reader使用单例模式IndexSearcher&ageQuery&topDocs&age&quot.for(int&new&nbsp.MUST));false),&nbsp,&nbsp.add(new&TopDocs&booleanQuery&nbsp,&scoreDocs&IndexSearcher(indexReader).doc(scoreDocs[i];=&new&i&new&=&i=0;=&nbsp,&;Integer(30);topDscoreDBooleanClause(ageQBooleanClause.search(booleanQuery.scoreDindexReader&nbsp
其他类似问题
为您推荐:
lucene的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁Lucene增量索引的搜索结果重复的问题 - 东升红日辉万里,明泽润物彻古今 - ITeye技术网站
博客分类:
Lucene的增量索引没有那么智能,虽然根据文档所言,把下面的第三个参数设为false就是增量索引(true to create the index or overwr false to append to the existing index,注意这个append)。但是我发现,它与true的区别,仅仅在于不去删掉以前所有的索引文件而已,他并不能智能的分析到当前要被索引的文件是否已经被索引过,因此对先前文档作了修改,要重建索引的话,必须删除先前的这个文档所对应的索引
new IndexWriter(indexDir, new StandardAnalyzer(), false, new IndexWriter.MaxFieldLength(10000));
建立索引的关键步骤就是对IndexWriter添加Document,我是对文本文件进行分析的
File f = new File("text.txt");
Document doc = new Document();
doc.add(new Field("content", new FileReader(f))); // 由于文件内容比较大,没有保存,如果是要做高亮搜索词的话,需要保存,分析,并且指定词向量参数Field.TermVector
doc.add(new Field("title", "要被索引的字符串", Field.Store.YES, Field.Index.ANALYZED));
writer.addDocument(doc);
参数的说明:
Field.Store.YES表示要对这个字符串进行存储,Field.Index.ANALYZED表示要对个字符串进行分析
虽然设置了增量索引,如果运行两次这个索引的代码,然后去搜索的话,会出现两条相同的结果。考虑到,一条doc对应一个文件,便想着给doc添加一个唯一标示的字段,索引之前检测是否存在,如果已经存在删除之
doc.add(new Field("fileid", "自定义的id", Field.Store.YES, Field.Index.NOT_ANALYZED));
保存这个id字段,但是不要对这个字段进行分析,如果分析了,对索引结果会有影响。刚开始计划使用文本路径设置id,但是不起作用,只有文件名的话可以,但没有唯一性,id的定制很重要。
删除doc的代码
writer.deleteDocuments(new Term("fileid", "自定义的id"));
关于是用IndexWriter来删除还是用IndexReader来删除可以参考下面文章
为保持数据一致,作者建议使用indexwriter来做删除操作
.....没明白我意思,不过我明白了! 谢谢你了doc.add(new Field("content", new FileReader(f)));FileReader方法为只读方法,没有能保存文件内容的属性。想要保存文件内容就只能将文件内容读取出来转换成字符串,利用下面的形式doc.add(new Field("title", "文件字符串", Field.Store.YES, Field.Index.ANALYZED));&&& 我还以为这种方法很笨,有更好的方法呢~!哎!!哈哈,不客气,祝贺。
大哥!我就最后问你一个问题! 就是读取文件建立索引doc.add(new Field("content", new FileReader(f)))这个是不是不能保存啊?所以查询的时候content为空。是不是只能保存字符串啊?没有更好的方法了吗~!请教下一 最后这一个问题!谢谢了!Field.Store.YES, Field.Index.ANALYZED看见了没,stroe yes这个参数就是保存,后面那个是分析,文本是可以保存的
大哥~!还有个问题请教下,就是按照你上面的方法读取TXT文件建立索引后,为什么搜索时候content就是文件内容为空呢~!还有大哥,如何获取文件内容摘要啊,小弟刚刚接触lucene好多地方发蒙,给贴点代码出来呗 最好相信点的 呵呵 谢谢了~!你上网搜一下,这个lucene的索引的文档,很多的,还有高亮代码之类的。你一定要搞明白哪些参数是什么意思,我没有时间给你一点点解释
请问下文件内容保存和高亮搜索的地方怎么做啊给你一段代码你参考一下吧 /**
* 获取高亮字符串
public String makeHighlight(String str) {
SimpleHTMLFormatter html_formater = new SimpleHTMLFormatter("&span class='search-highlight'&", "&/span&");
Highlighter highlighter = new Highlighter(html_formater, new QueryScorer(query));
highlighter.setTextFragmenter(new SimpleFragmenter(200));
String re_str = "";
if (str != null) {
TokenStream tokenStream = new IKAnalyzer().tokenStream("", new StringReader(str));
re_str = highlighter.getBestFragment(tokenStream, str);
if(re_str == null || "".equals(re_str)) re_str =
} catch (IOException ex) {
} catch (InvalidTokenOffsetsException ex) {
return re_
大哥 又没遇到过compass查询重复的问题 应该也是索引重复了 没头绪啊 qq 这个没用过,避免重复索引的话,设置一个 唯一标示的id ,下一次再去索引的时候,把以前的干掉,再重建。昨天还看到一个方法,就是根据id找到索引,然后更新其中的一些域
hotsunshine
浏览: 283855 次
来自: 北京
$(&某一个dom&).change()
非常感谢,我的也是磁盘满了导致的问题,顺便分享下查看磁盘的命令 ...
vikki 写道沙发先。楼主,这些代码例子你都运行过吗?运行过 ...
沙发先。楼主,这些代码例子你都运行过吗?

我要回帖

更多关于 lucene查询所有数据 的文章

 

随机推荐