主要内容:组合关键词搜索、关键词的解析、多索引搜索、多线程搜索
1. 构建多种搜索请求
前面介绍了使用 TermQuery 构建最基本的搜索,即普通的关键词搜索。
在 Lucene 中,使用 Query 对象封装搜索请求。 Query 类本身是一个抽象类,其不同的子类( TermQuery 、 BooleanQuery )分别用来构建不同的搜索请求。
1.1 词条搜索 TermQuery
词条搜索就是 TermQuery 。首先构建 Term ,然后以 Term 为对象构建 TermQuery ,代码如下:
Term t = new Term( 被搜索的 Field, 搜索关键词 );
TermQuery q = new TermQuery(t);
示例: Test.Java 词条搜索
1.2 组合搜索 BooleanQuery
使用 BooleanQuery 对象封装组合搜索请求,与 或 非
用法:首先构建多个 TermQuery ,然后以多个 TermQuery 为参数构建 BooleanQuery ,在多个 Term 之间进行逻辑运算。例如:
Term t1 = new Term("text", "love");
TermQuery q1 = new TermQuery(t1);
Term t2 = new Term("text", "mother");
TermQuery q2 = new TermQuery(t2);
BooleanQuery q = new BooleanQuery();
q.add(q1,BooleanClause.Occur.MUST);
q.add(q2,BooleanClause.Occur.MUST);
BooleanQuery 对象的 add 方法将 TermQuery 对象添加进来,第一个参数是 TermQuery 对象,第二个参数是该 TermQuery 对象的逻辑表达,有三个取值:
BooleanClause.Occur.MUST 搜索结果必须满足该 Term
BooleanClause.Occur.MUST_NOT 搜索结果必须排除该 Term
BooleanClause.Occur.SHOULD 搜索结果可以满足该 Term
利用这三个值可以在 TermQuery 之间构造多种逻辑关系
BooleanClause.Occur.MUST 和 BooleanClause.Occur.MUST 组合在一起:逻辑与
BooleanClause.Occur.MUST_NOT :逻辑非
BooleanClause.Occur.SHOULE :逻辑或
BooleanQuery 对象所支持的子查询数量默认情况下最多 1024 个,可以通过 setMaxClauseCount(int num) 方法修改这个默认值。子查询数量少,查询速度会加快。
1.3 范围搜索 RangeQuery
搜索结果处于某个范围之内。使用 RangeQuery 对象来封装范围搜索的请求,构造方法:
RangeQuery(Term lowerTerm, Term upperTerm, Boolean inclusive);
第一个参数是起始 Term ,第二个参数是终止 Term ,第三个参数表示是否包含边界(是否包含起始 Term )
Term tb = new Term("id", "0");
Term te = new Term("id", "2");
RangeQuery q = new RangeQuery(tb,te,true);
用 ID 号限定的范围
1.4 前缀搜索 PrefixQuery
如搜索“标题前三个字是‘大中华’”,就需要用到前缀搜索
Lucene 专门提供类 PrefixQuery 处理这种搜索。
Term t = new Term("text", "genius");
PrefixQuery q = new PrefixQuery(t);
1.5 短语搜索 PhraseQuery
PhraseQuery 类把一些短语组合起来形成新的短语。在这种搜索类型中可以设置匹配度。
可以用 PhraseQuery 把“鼠”和“标”组合成“鼠标”这个短语。也可以设置间隔量的方法,将其组合成“鼠 *** 标”,从而使得“老鼠爱上标”这样的结果也符合条件,实现模糊匹配。
使用方法:首先建立几个 Term ,然后按顺序添加到 PhraseQuery 中。
方法 setSlop(int s) 可以设定允许 Term 词语之间间隔的字符数量,不设为 0 。
Term t1 = new Term("text", " 鼠 ");
Term t2 = new Term("text", " 标 ");
PhraseQuery q = new PhraseQuery();
q.setSlop(1); // 设置间隔
q.add(t1);
q.add(t2);
1.6 多短语搜索 MultiPhraseQuery
相当于首先指定一个前缀,然后把其它词语加在后面,形成新的词语。
例如,指定“飞”作为统一前缀,然后指定“鸟”、“机”为后缀, Lucene 会自动组成“飞鸟”、“飞机”两个词进行搜索。
Term t = new Term("text", " 飞 ");
Term t1 = new Term("text", " 鸟 ");
Term t2 = new Term("text", " 机 ");
MultiPhraseQuery q = new MultiPhraseQuery();
// 统一前缀
q.add(t);
// 后续
q.add(new Term[]{t1,t2});
1.7 模糊搜索 FuzzyQuery
用于西文搜索,如果两个词词形相似,那么可以设定匹配度,从而搜索出结果。
如,使用了 FuzzyQuery 就可以使搜索引擎把用户输入的“ good ”当作“ god ”处理
Term t = new Term(“text”, “god”);
FuzzyQuery q = new FuzzyQuery(t, 0.6f);
第二个参数是模糊度,一个 float 值,默认为 0.5 ,越小模糊性越强
1.8 通配符搜索 WildcardQuery
“ * ”表示任意多个字符,“?”表示任意一个字符
Term t = new Term(“text”, “ 飞? ”);
WildcardQuery q = new WildcardQuery(t);
对于经过分词的文本域,这种搜索的意义不大
1.9 正则表达式匹配搜索 RegexQuery
正则表达式匹配搜索集匹配搜索之大成,是最有用的模糊搜索。该类目前还不属于 Lucene 的标准类,如需使用要把 contrib/regex 下的 Lucene-regex-2.1.0.jar 添加到编译路径中。
Term t = new Term(“text”, “ 正则表达式 ”);
RegexQuery q = new RegexQuery(t);
例:正则表达式 “^ 飞 ” 表示以非开头的词语
1.10 综述
Lucene 的搜索类很多,并不止上面介绍的这些。
TermQuery 和 BooleanQuery 是根本。功能最强的是 RegexQuery ,掌握这三个类即可,其它的搜索类可以很容易自己构造。
2. 解析搜索请求
按照设定好的某种逻辑分析用户搜索的真实意图。解析搜索请求属于前端分析,针对的是用户输入的关键词。 Lucene 提供 QueryParser 类用来解析搜索请求。
QueryParser 类可以进行与或非的处理,还可以进行通配符识别和范围搜索识别等。不过作者并不推荐使用 QueryParser 类进行搜索请求解析工作,而是把搜索请求处理放在搜索引擎程序前面一层的应用程序中。
2.1 QueryParser 类的基本使用
其代码位置与 TermQuery 相同
import org.apache.lucene.queryParser.QueryParser;
QueryParser parser = QueryParser(“ 字段名称 ”, “ 分析器实例 ”);
Query q = parser.parse(“ 关键词 ”);
示例:
//IndexSearcher
IndexSearcher searcher = new IndexSearcher(rd);
//Term & Query
String searchField = "text";
String searchPhrase = "love ";
QueryParser parser = new QueryParser(searchField,new StandardAnalyzer());
Query q = parser.parse(searchPhrase);
System.out.println(q);
//Hits
Hits hs = searcher.search(q);
结果:
将搜索请求解析为: text:love
2.2 解析多个关键词
如果搜索关键词是 String searchPhrase = "love mother"; 那么输出结果将是
text:love text:mother
也即 Lucene 把输入的关键词按照逻辑或的关系进行了处理。
我们可以修改这种逻辑,让其以逻辑与的关系处理
String searchField = "text";
String searchPhrase = "love mother";
QueryParser parser = new QueryParser(searchField,new StandardAnalyzer());
parser.setDefaultOperator(QueryParser.Operator.AND); // 默认是 OR
Query q = parser.parse(searchPhrase);
System.out.println(q);
解析结果: +text:love +text:mother
在“ text ”字段搜索 love ,在 text 字段搜索 mother ,两部分结果取公共部分
setDefaultOperator 的默认参数是 QueryParser.Operator.OR
3. 高级搜索
主要内容:多字段搜索、多索引搜索、多线程搜索
3.1 多字段搜索
一个文档含有“标题”、“正文”等字段,搜索一个关键词,不管在“标题”还是“正文”中出现都满足条件,就是多字段搜索。
( 1 )利用 BooleanQuery 实现多字段搜索
前面已经介绍,首先设置两个 TermQuery ,再进行逻辑或运算即可。
Term t1 = new Term("text", "love");
TermQuery q1 = new TermQuery(t1);
Term t2 = new Term("id", "love");
TermQuery q2 = new TermQuery(t2);
BooleanQuery q = new BooleanQuery();
q.add(q1,BooleanClause.Occur.SHOULD);
q.add(q2,BooleanClause.Occur.SHOULD);
( 2 )利用 MultiFieldQuery 实现多字段搜索
Lucene 专门提供了 MultiFieldQueryParser 类,用来实现多字段搜索。其实,它只是对 BooleanQuery 封装。
构造方法:
MultiFieldQueryParser(String[] fields, Analyzer analyzer)
第一个参数是多个字段名称组成的数组,第二个参数是分析器实例
使用方法:
String[] fields = {“text”, “id”};
MultiFieldQueryParser mp = new MultiFieldQueryParser(fields, new StandardAnalyzer());
Query q = mp.parse(“love”);
( 3 )封装的方法
自定义函数实现,这也是 MultiFieldQueryParser 类的实现方法
String[] fields = {"text","id"};
String phrase = "love";
Query q = my(fields,phrase);
函数
public static BooleanQuery my(String fields[],String phrase)
{
int len = fields.length;
BooleanQuery q = new BooleanQuery();
for(int i=0;i<len;i++)
{
String fie = fields[i];
Term t = new Term(fie,phrase);
TermQuery tq = new TermQuery(t);
q.add(tq,BooleanClause.Occur.SHOULD);
}
return q;
}
3.2 多索引搜索
为了减少单个索引目录的大小,时常将索引放在许多目录中,这些目录的结构是一致的。
要实现多索引搜索,只需对每个索引目录都用 IndexSearcher 搜索一遍,最后将结果合并。
Lucene 专门提供了 MultiSearcher 类实现多索引搜索。方法如下:
IndexSearcher searcher1 = new IndexSearcher("index1");
IndexSearcher searcher2 = new IndexSearcher("index2");
IndexSearcher[] searchers = {searcher1,searcher2};
MultiSearcher searcher = new MultiSearcher(searchers);
建立 MultiSearcher 对象后,使用方法就和 IndexSearcher 一样了
最后关闭搜索器的时候,只需关闭 MultiSearcher 的实例,在关闭它的时候,相应的几个 IndexSearcher 也被关闭了。
3.3 多线程搜索
MultiSearcher 的实现机制是对 IndexSearcher 数组中的每个 IndexSearcher 对象执行搜索,得到搜索结果后进行合并,它们是串行进行的。
Lucene 提供了 ParallelMultiSearcher 类实现多线程搜索,它是 MultiSearcher 的子类,使用方法与 MultiSearcher 一致。
IndexSearcher searcher1 = new IndexSearcher("index1");
IndexSearcher searcher2 = new IndexSearcher("index2");
IndexSearcher[] searchers = {searcher1,searcher2};
ParallelMultiSearcher searcher = new ParallelMultiSearcher(searchers);