Lucene搜索方法总结

转自:summerbell
http://www.iteye.com/topic/569358

1.多字段搜索

使用 multifieldqueryparser 可以指定多个搜索字段。

query query = multifieldqueryparser.parse(”name*”, new string[] { fieldname, fieldvalue }, analyzer);

indexreader reader = indexreader.open(directory);

indexsearcher searcher = new indexsearcher(reader);

hits hits = searcher.search(query);

2.多条件搜索

除了使用 queryparser.parse 分解复杂的搜索语法外,还可以通过组合多个 query 来达到目的。

query query1 = new termquery(new term(fieldvalue, “name1′)); // 词语搜索

query query2 = new wildcardquery(new term(fieldname, “name*”)); // 通配符

//query query3 = new prefixquery(new term(fieldname, “name1′)); // 字段搜索 field:keyword,自动在结尾添加 *

//query query4 = new rangequery(new term(fieldnumber, numbertools.longtostring(11l)), new term(fieldnumber, numbertools.longtostring(13l)), true); // 范围搜索

//query query5 = new filteredquery(query, filter); // 带过滤条件的搜索

booleanquery query = new booleanquery();

query.add(query1, booleanclause.occur.must);

query.add(query2, booleanclause.occur.must);

indexsearcher searcher = new indexsearcher(reader);

hits hits = searcher.search(query);

3.过滤

使用 filter 对搜索结果进行过滤,可以获得更小范围内更精确的结果。

举个例子,我们搜索上架时间在 2005-10-1 到 2005-10-30 之间的商品。

对于日期时间,我们需要转换一下才能添加到索引库,同时还必须是索引字段。 // index

document.add(fielddate, datefield.datetostring(date), field.store.yes, field.index.un_tokenized);

//…

// search

filter filter = new datefilter(fielddate, datetime.parse(”2005-10-1′), datetime.parse(”2005-10-30′));

hits hits = searcher.search(query, filter);

除了日期时间,还可以使用整数。比如搜索价格在 100 ~ 200 之间的商品。

lucene.net numbertools 对于数字进行了补位处理,如果需要使用浮点数可以自己参考源码进行。 // index

document.add(new field(fieldnumber, numbertools.longtostring((long)price), field.store.yes, field.index.un_tokenized));

//…

// search

filter filter = new rangefilter(fieldnumber, numbertools.longtostring(100l), numbertools.longtostring(200l), true, true);

hits hits = searcher.search(query, filter);

使用 query 作为过滤条件。 queryfilter filter = new queryfilter(queryparser.parse(”name2′, fieldvalue, analyzer));

我们还可以使用 filteredquery 进行多条件过滤。

filter filter = new datefilter(fielddate, datetime.parse(”2005-10-10′), datetime.parse(”2005-10-15′));

filter filter2 = new rangefilter(fieldnumber, numbertools.longtostring(11l), numbertools.longtostring(13l), true, true);

query query = queryparser.parse(”name*”, fieldname, analyzer);

query = new filteredquery(query, filter);

query = new filteredquery(query, filter2);

indexsearcher searcher = new indexsearcher(reader);

hits hits = searcher.search(query);

4.分布搜索

我们可以使用 multireader 或 multisearcher 搜索多个索引库。

multireader reader = new multireader(new indexreader[] { indexreader.open(@”c:\index”), indexreader.open(@”\\server\index”) });

indexsearcher searcher = new indexsearcher(reader);

hits hits = searcher.search(query);

indexsearcher searcher1 = new indexsearcher(reader1);

indexsearcher searcher2 = new indexsearcher(reader2);

multisearcher searcher = new multisearcher(new searchable[] { searcher1, searcher2 });

hits hits = searcher.search(query);

还可以使用 parallelmultisearcher 进行多线程并行搜索。

5.显示搜索语法字符串

我们组合了很多种搜索条件,或许想看看与其对等的搜索语法串是什么样的。 booleanquery query = new booleanquery();

query.add(query1, true, false);

query.add(query2, true, false);

//…

console.writeline(”syntax: {0}”, query.tostring());

输出:

syntax: +(name:name* value:name*) +number:[0000000000000000b to 0000000000000000d]

呵呵,就这么简单。

6.如何删除索引

lucene提供了两种从索引中删除document的方法,一种是

void deleteDocument(int docNum)

这种方法是根据document在索引中的编号来删除,每个document加进索引后都会有个唯一编号,所以根据编号删除是一种精确删除,但是这个编号是索引的内部结构,一般我们不会知道某个文件的编号到底是几,所以用处不大。另一种是

void deleteDocuments(Term term)

这种方法实际上是首先根据参数term执行一个搜索操作,然后把搜索到的结果批量删除了。我们可以通过这个方法提供一个严格的查询条件,达到删除指定document的目的。

下面给出一个例子:

Directory dir = FSDirectory.getDirectory(PATH, false);

IndexReader reader = IndexReader.open(dir);

Term term = new Term(field, key);

reader.deleteDocuments(term);

reader.close();

ms还有操作

deleteDocuments(Term);   deleteDocuments(Term[]);   deleteDocuments(Query);   deleteDocuments(Query[]);

7.如何更新索引

注:据多人反应,新版本的lucene以及提供了更新索引的方法。

writer.updateDocument(doc);

————————————————————javaeye分割线——————————————

lucene并没有提供专门的索引更新方法,我们需要先将相应的document删除,然后再将新的document加入索引。例如:

Directory dir = FSDirectory.getDirectory(PATH, false);

IndexReader reader = IndexReader.open(dir);

Term term = new Term(“title”, “lucene introduction”);

reader.deleteDocuments(term);

reader.close();

IndexWriter writer = new IndexWriter(dir, new StandardAnalyzer(), true);

Document doc = new Document();

doc.add(new Field("title", "lucene introduction", Field.Store.YES, Field.Index.TOKENIZED));

doc.add(new Field("content", "lucene is funny", Field.Store.YES, Field.Index.TOKENIZED));

writer.addDocument(doc);

writer.optimize();

writer.close();

8.多样化的搜索

/** *** 一个关键字,对一个字段进行查询 **** */

QueryParser qp = new QueryParser("content",analyzer);

query = qp.parse(keyword);

Hits hits = searcher.search(query);

/** *** 模糊查询 **** */

Term term = new Term("content",keyword);

FuzzyQuery fq = new FuzzyQuery(term);

Hits hits = searcher.search(fq);

/** *** 一个关键字,在两个字段中查询 **** */

/*

* 1.BooleanClause.Occur[]的三种类型: MUST : + and MUST_NOT : - not SHOULD : or

* 2.下面查询的意思是:content中必须包含该关键字,而title有没有都无所谓

* 3.下面的这个查询中,Occur[]的长度必须和Fields[]的长度一致。每个限制条件对应一个字段

*/

BooleanClause.Occur[] flags = new BooleanClause.Occur[]{BooleanClause.Occur.SHOULD,BooleanClause.Occur.MUST};

query=MultiFieldQueryParser.parse(keyword,new String[]{"title","content"},flags,analyzer);

/** *** 两个(多个)关键字对两个(多个)字段进行查询,默认匹配规则 **** */

/*

* 1.关键字的个数必须和字段的个数相等

* 2.由于没有指定匹配规定,默认为"SHOULD" 因此,下面查询的意思是:"title"中含有keyword1 或 "content"含有keyword2.

* 在此例中,把keyword1和keyword2相同

*/

query=MultiFieldQueryParser.parse(new String[]{keyword,keyword},new

String[]{"title","content"},analyzer);

/** *** 两个(多个)关键字对两个(多个)字段进行查询,手工指定匹配规则 **** */

/*

* 1.必须 关键字的个数 == 字段名的个数 == 匹配规则的个数

* 2.下面查询的意思是:"title"必须不含有keyword1,并且"content"中必须含有keyword2

*/

BooleanClause.Occur[] flags = new

BooleanClause.Occur[]{BooleanClause.Occur.MUST_NOT,BooleanClause.Occur.MUST};

query=MultiFieldQueryParser.parse(new String[]{keyword,keyword},new

String[]{"title","content"},flags,analyzer);

/** *** 对日期型字段进行查询 **** */

/** *** 对数字范围进行查询 **** */

/*

* 1.两个条件必须是同一个字段

* 2.前面一个条件必须比后面一个条件小,否则找不到数据

*  3.new RangeQuery中的第三个参数,表示是否包含"=" true: >= 或 <= false: > 或 <

* 4.找出 55>=id>=53 or 60>=id>=57:

*/

Term lowerTerm1 = new Term("id","53");

Term upperTerm1 = new Term("id","55");

RangeQuery rq1 = new RangeQuery(lowerTerm1,upperTerm1,true);

Term lowerTerm2 = new Term("id","57");

Term upperTerm2 = new Term("id","60");

RangeQuery rq2 = new RangeQuery(lowerTerm2,upperTerm2,true);

BooleanQuery bq = new BooleanQuery();

bq.add(rq1,BooleanClause.Occur.SHOULD);

bq.add(rq2,BooleanClause.Occur.SHOULD);

Hits hits = searcher.search(bq);

9.结果排序

排序的关键点有两个:

1:首先你要排序的字段必须是被index的,并且是untokenized的。

如:

doc.add(new Field("click", dv.get("click").toString(), Field.Store.NO, Field.Index.UN_TOKENIZED));

2:在检索时候:

如:

/*****  排序  *****/

/*

* 1.被排序的字段必须被索引过(Indexecd),在索引时不能 用 Field.Index.TOKENIZED

*   (用UN_TOKENIZED可以正常实现.用NO时查询正常,但排序不能正常设置升降序)

* 2.SortField类型

*   SCORE、DOC、AUTO、STRING、INT、FLOAT、CUSTOM 此类型主要是根据字段的类型选择

* 3.SortField的第三个参数代表是否是降序true:降序  false:升序

*/

Sort sort = new Sort(new SortField[]{new SortField("click", SortField.INT, true)});

Hits hits = searcher.search(querystring,sort);

/*

* 按日期排序

*/

Sort sort = new Sort(new SortField[]{new SortField("createTime", SortField.INT, false)});

/*****  过滤器 ******/

QueryParser qp1 = new QueryParser("content",analyzer);

Query fquery  = qp1.parse("我");

BooleanQuery bqf = new BooleanQuery();

bqf.add(fquery,BooleanClause.Occur.SHOULD);

QueryFilter qf = new QueryFilter(bqf);

Hits hits = searcher.search(query);

10.将小索引文件合并到大的索引文件中去(此方法性能不佳)

/** 将小索引文件合并到大的索引文件中去

*   @param   from   将要合并到to文件的文件

*   @param   to       将from文件合并到该文件

*   @param   analyzer

*/

private   void   mergeIndex(File   from,File   to,Analyzer   analyzer)

{

IndexWriter   indexWriter   =   null;

try{

System.out.println("正在合并索引文件!\t");

indexWriter   =   new   IndexWriter(to,analyzer,   false);

indexWriter.setMergeFactor(100000);

indexWriter.setMaxFieldLength(Integer.MAX_VALUE);

indexWriter.setMaxBufferedDocs(Integer.MAX_VALUE);

indexWriter.setMaxMergeDocs(Integer.MAX_VALUE);

FSDirectory[]   fs   =   {FSDirectory.getDirectory(from,false)};

indexWriter.addIndexes(fs);

indexWriter.optimize();

indexWriter.close();

System.out.println("已完成合并!\t");

}

catch(Exception   e)

{

Utility.writeLog("合并索引文件出错!mergeIndex()"+e.getMessage(),"");

}

finally

{

try{

if(indexWriter!=null)

indexWriter.close();

}

catch(Exception   e   ){

}

}

}

合并时间是从每天的凌晨3点钟开始,一直到早上9点左右,足足用5个小时才合并完成,其中大索引文件大小为4G,小索引为10MB.

11.问题2:单字共现频率的局部统计的原理

解答:

高频字串统计的理论基础是N - 元模型。

设W1 W2 ...WN 是长度为N 的字串,则字串W 的似然度为 p ( W) = p ( w i | w1 w2 ...w i - 1) (1) 上面公式的意义反映连续个N 字之间的结合程度,如果若干种不同的历史组合W1 W2 ...WN的最后N - 1 个字相同,就把它们都看作一类。在这一假设下,每一个字出现的概率不再与前面的历史有关,只与最近的N - 1 个字相关,字串的先验概率为 p ( W) = p ( w i - ( n - 1) w i - ( n - 2) ...w i - 1) (2) 当p ( W) 超过一定的阈值时,说明这N 个字的结合能力较强,我们就可以认为该字串能被看成一个“词”。

正是根据以上所说原理,预先对待分词文本每个单字进行出现次数统计并记录它们在文中出现的位置(存储方式如附件图例所示),预处理后我们遍历单字频次统计 列表出现次数大于2的所有单字在文中出现的位置i,判断位置i+1的单字出现次数是否也大于2,若是则判断位置i+2的单字出现次数是否也大于2,如此类 推直至位置i+n+1的单字出现次数小于2,获得候选词组 w(i,i+1...i+n)并放入候选词汇集合,最后对候选词汇集合进行前缀后缀处理获得合适的高频词汇集合result

12.索引合并

writer.addIndexes(indexDirs);

时间: 2024-10-10 01:42:50

Lucene搜索方法总结的相关文章

一步一步跟我学习lucene(13)---lucene搜索之自定义排序的实现原理和编写自己的自定义排序工具

自定义排序说明 我们在做lucene搜索的时候,可能会需要排序功能,虽然lucene内置了多种类型的排序,但是如果在需要先进行某些值的运算然后在排序的时候就有点显得无能为力了: 要做自定义查询,我们就要研究lucene已经实现的排序功能,lucene的所有排序都是要继承FieldComparator,然后重写内部实现,这里以IntComparator为例子来查看其实现: IntComparator相关实现 其类的声明为 public static class IntComparator exte

使用 Apache Lucene 搜索文本

好东西 下手绝不留情 转自 http://www.ibm.com/developerworks/cn/opensource/os-apache-lucenesearch/ 简介 Lucene 是一个开源.高度可扩展的搜索引擎库,可以从 Apache Software Foundation 获取.您可以将 Lucene 用于商业和开源应用程序.Lucene 强大的 API 主要关注文本索引和搜索.它可以用于为各种应用程序构建搜索功能,比如电子邮件客户端.邮件列表.Web 搜索.数据库搜索等等.Wi

一步一步跟我学习lucene(12)---lucene搜索之分组处理group查询

grouping介绍 我们在做lucene搜索的时候,可能会用到对某个条件的数据进行统计,比如统计有多少个省份,在sql查询中我们可以用distinct来完成类似的功能,也可以用group by来对查询的列进行分组查询.在lucene中我们实现类似的功能怎么做呢,比较费时的做法时我们查询出所有的结果,然后对结果里边的省份对应的field查询出来,往set里边放,显然这种做法效率低,不可取:lucene为了解决上述问题,提供了用于分组操作的模块group,group主要用户处理不同lucene中含

一步一步跟我学习lucene(8)---lucene搜索之索引的查询原理和查询工具类示例

昨天我们了解了lucene搜索之IndexSearcher构建过程(http://blog.csdn.net/wuyinggui10000/article/details/45698667),对lucene的IndexSearcher有一个大体的了解,知道了怎么创建IndexSearcher,就要开始学会使用IndexSearcher进行索引的搜索,本节我们学习索引的查询原理和根据其相关原理写索引查询的工具类的编写: IndexSearcher提供了几个常用的方法: IndexSearcher.

一步一步跟我学习lucene(7)---lucene搜索之IndexSearcher构建过程

最近一直在写一步一步跟我学习lucene系列(http://blog.csdn.net/wuyinggui10000/article/category/3173543),个人的博客也收到了很多的访问量,谢谢大家的关注,这也是对我个人的一个激励,O(∩_∩)O哈哈~,个人感觉在博客的编写过程中自己收获了很多,我会一直继续下去,在工作的过程中自己也会写出更多类似系列的博客,也算是对自己只是的一种积累: IndexSearcher 搜索引擎的构建分为索引内容和查询索引两个大方面,这里要介绍的是luce

Lucene搜索方式大合集

package junit; import java.io.File; import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.math.NumberUtils; import org.apache.lucene.document.Document; import or

lucene 搜索demo

package com.ljq.utils; import java.io.File; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import org.apache.lucene.document.Document; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.Inde

lucene搜索方式(query类型)

Lucene有多种搜索方式,可以根据需要选择不同的方式. 1.词条搜索(单个关键字查找) 主要对象是TermQuery 调用方式如下: Term term=new Term(字段名,搜索关键字);Query query=new TermQuery(term);Hits hits=searcher.search(query); 2.组合搜索(允许多个关键字组合搜索) 主要对象是BooleanQuery 调用方式如下: Term term1=new Term(字段名,搜索关键字);TermQuery

es lucene搜索及聚合流程源码分析

本文以TermQuery,GlobalOrdinalsStringTermsAggregator为例,通过代码,分析es,lucene搜索及聚合流程.1:协调节点收到请求后,将search任务发到相关的各个shard. 相关代码: TransportSearchAction.executeSearch TransportSearchAction.searchAsyncAction.start AbstractSearchAsyncAction.executePhase(SearchQueryTh