在前面我们提到了,Lucene使用IndexSearcher进行搜索,Lucene作为一个开源的搜索工具包,为开发人员提供了丰富的查询方法,在本节中,我们将讨论不同类型的查询对象和方法。
为了方便看效果,先新建一个类,将我们给定的数据建立索引存放在内存里面
/**
*
* 类名: LuceneQueryAll.java
* 包: com.travelsky.pss.react.cn.lucene.query
* 描述: TODO
* @author tanjie
* 创建时间: 2015-11-5 下午12:44:31
* @version V1.2.0
*/
public class LuceneQueryAll {
private Directory directory;
private IndexReader reader;
private String[] moneys = { "100", "200", "300", "400", "500", "600" };
private String[] emails = { "aa@travelsky.com", "bb@travelsky.com",
"cc@travelsky.com", "dd@travelsky.com", "ee@travelsky.com",
"ff@travelsky.com" };
private String[] contents = { "welcome to chongqing",
"hello boy, I like pingpeng ball", "my name is cc I like game",
"I like hehe" , "I like football and I like basketball too",
"I like haha" };
private String[] names = { "zhangsan", "lisi", "tom", "jetty", "mike",
"jake" };
public LuceneQueryAll() {
//索引存储在内存中
directory = new RAMDirectory();
index();
}
/**
*
* @author tanjie
* 创建时间: 2015-11-5 下午1:01:19
* 描述: 在内存中简历索引
*/
public void index() {
IndexWriter writer = null;
try {
writer = new IndexWriter(directory, new IndexWriterConfig(
Version.LUCENE_4_9,
new StandardAnalyzer(Version.LUCENE_4_9)));
writer.deleteAll();
Document doc = null;
for (int i = 0; i < ids.length; i++) {
doc = new Document();
doc.add(new TextField("money", moneys[i], Field.Store.YES));
doc.add(new TextField("email", emails[i], Field.Store.YES));
//为了便于观察,我们将内容也存储
doc.add(new TextField("content", contents[i], Field.Store.YES));
doc.add(new TextField("name", names[i], Field.Store.YES));
writer.addDocument(doc);
}
writer.commit();
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (LockObtainFailedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (writer != null) {
writer.close();
}
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
*
* @author tanjie
* 创建时间: 2015-11-5 下午1:02:12
* 描述: TODO
* @return IndexSearcher
*/
public IndexSearcher getSearcher() {
try {
if (reader == null) {
reader = DirectoryReader.open(directory);
}
return new IndexSearcher(reader);
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
TermQuery 是Lucene提供的最基本的一个查询类,从它的构造函数中,我们可以看到它接收的是一个Term对象。Term是一个词条,所以TermQuery是按 照词条进行查询的,词条我们可以将其理解为某个字段的名称,也就是我们要精确搜索到某一个域里面存在某个词条的文档时,TermQuery就起作用了
下面的测试类,我们要精确搜索在域money里面,有200元钱的文档,获得其详细信息。
/**
*
* @author tanjie* 创建时间: 2015-11-5 下午12:16:46
* 描述: 精确查找
* @param field 查找的域
* @param name 查找的词
* @param num 最多显示多少个
*/
public void searchByTerm(String field, String name, int num) {
try {
IndexSearcher searcher = getSearcher();
Query query = new TermQuery(new Term(field, name));
TopDocs tds = searcher.search(query, num);
System.out.println("一共查询了:" + tds.totalHits + "条记录");
for (final ScoreDoc sd : tds.scoreDocs) {
Document doc = searcher.doc(sd.doc);
System.out.println("我有:" + doc.get("money") + "块,名字为" + doc.get("name")
+ ",邮箱为[" + doc.get("email") + "] ");
}
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void testSearchByTerm() {
LuceneQueryAll luceneQueryAll = new LuceneQueryAll();
luceneQueryAll.searchByTerm("money", "200", 10);
}
运行上面的测试类,运行结果如下:
一共查询了:1条记录
我有:200块,名字为:lisi,邮箱为[bb@travelsky.com]
我们知道,当我们简单的在百度输入一个关键字,然 后点击搜索就可以获得大量的和你搜索的内容相关的文档了,因为搜索引擎帮你做了很多事,而在Lucene中,这项工作就交给了QueryParser类来 完成,QueryParser实际上就是一个解析用户输入的工具,它通过扫描用户输入的字符串然后将其转为一个内部的Query对象。
下面的测试类,我们通过制定搜索的域,解析输入的关键字,来进行搜索。
/**
*
* @author tanjie
* 创建时间: 2015-11-5 下午12:24:08
* 描述: 根据特定的分析器搜索
* @param field 查询域
* @param keyword 搜索关键字
* @param num 最多显示多少条
*/
public void searchByQueryParse(String field,String keyword, int num) {
try {
IndexSearcher searcher = getSearcher();
QueryParser queryParser = new QueryParser(Version.LUCENE_4_9, field,
new StandardAnalyzer(Version.LUCENE_4_9));
Query query = queryParser.parse(keyword);
TopDocs tds = searcher.search(query, num);
System.out.println("一共查询了:" + tds.totalHits +"条记录");
for (final ScoreDoc sd : tds.scoreDocs) {
Document doc = searcher.doc(sd.doc);
System.out.println("我有:" + doc.get("money") + "块,名字为" + doc.get("name")
+ ",邮箱为[" + doc.get("email") + "] ");
}
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
@Test
public void testQueryParser() {
LuceneQueryAll luceneQueryAll = new LuceneQueryAll();
luceneQueryAll.searchByQueryParse("name","zhangsan", 10);
}
运行上面的测试类,运行结果如下:
一共查询了:1条记录
我有100块,名字为:zhangsan,邮箱为[aa@travelsky.com]-->
BooleanQuery其实是多个Query的组 合,我们有时候在搜索的时候,需要结合多个搜索条件,而BooleanQuery则是将多个Query对象添加进来,每个Query由用户指定不同的逻辑 关系,而且,一个BoolenQuery同时也可以嵌套在另一个BooleanQuery里面。
下面的测试类表示我们要搜索索引里面名字不为张三,且内容可以出现game对应的文档。
/**
*
* @author tanjie
* 创建时间: 2015-11-5 下午12:34:56
* 描述: 与或 查询
* @param num 最多显示多少条
*/
public void searchByBoolean(int num) {
try {
IndexSearcher searcher = getSearcher();
BooleanQuery query = new BooleanQuery();
/*
* BooleanQuery可以连接多个子查询 ,Occur.MUST表示必须出现,
Occur.SHOULD表示可以出现,Occur.MUSE_NOT表示不能出现
*/
query.add(new TermQuery(new Term("name", "zhangsan")),
Occur.MUST_NOT);
query.add(new TermQuery(new Term("content", "game")), Occur.SHOULD);
TopDocs tds = searcher.search(query, num);
System.out.println("一共查询了:" + tds.totalHits + "条记录");
for (final ScoreDoc sd : tds.scoreDocs) {
Document doc = searcher.doc(sd.doc);
System.out.println("我有" + doc.get("money") + "块,名字为:" + doc.get("name")
+ ",邮箱为[" + doc.get("email") + "] " + ",内容为: " + "[" + doc.get("content") + "]");
}
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void testSearchByBoolean() {
LuceneQueryAll luceneQueryAll = new LuceneQueryAll();
luceneQueryAll.searchByBoolean(10);
}
运行上面的测试类,运行结果如下:
一共查询了:3条记录
我有400块,名字为jetty,邮箱为[dd@travelsky.com],内容为: [I like football game]
我有200块,名字为lisi, 邮箱为[bb@travelsky.com],内容为: [hello boy, I like pingpeng ball game]
我有300块,名字为john, 邮箱为[cc@travelsky.com] ,内容为: [my name is cc I like game]
PrefixQuery就是使用前缀来进行查找的。通常情况下,首先定义一个词条Term。该词条包含要查找的字段名以及关键字的前缀,然后通过该词条构造一个PrefixQuery对象,就可以进行前缀查找了。
/**
*
* @author tanjie
* 创建时间: 2015-11-5 下午12:48:36
* 描述: 根据前缀搜索
* @param field 搜索的域
* @param value 搜索的值
* @param num 最多显示多少条记录
* void
*/
public void searchByPrefix(String field, String value, int num) {
try {
IndexSearcher searcher = getSearcher();
Query query = new PrefixQuery(new Term(field, value));
TopDocs tds = searcher.search(query, num);
System.out.println("一共查询了:" + tds.totalHits + "条记录");
for (final ScoreDoc sd : tds.scoreDocs) {
Document doc = searcher.doc(sd.doc);
System.out.println("我有" + doc.get("money") + "块,名字为:" + doc.get("name")
+ ",邮箱为[" + doc.get("email") + "] " + ",内容为: " + "[" + doc.get("content") + "]");
}
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void testSearchByPrefix() {
LuceneQueryAll luceneQueryAll = new LuceneQueryAll();
//搜索域为email,前缀为aa的结果,最多显示10条
luceneQueryAll.searchByPrefix("email","aa", 10);
}
运行上面的测试类,运行结果如下:
一共查询了:1条记录
我有100块,名字为:zhangsan,邮箱为[aa@travelsky.com],内容为: [welcome to chongqing game,I like eat]
FuzzyQuery是Lucene提供的一个用来模糊匹配的Query,比如,在我们的索引里面。域name对应的词中有,mike,make,mikes等,我们可以通过FuzzyQuery 来实现只搜索mike即搜索出与之相近的文档。
/**
*
* @author tanjie
* 创建时间: 2015-11-5 下午12:58:58
* 描述: 模糊查询FuzzyQuery
* @param num
*/
public void searchByFuzzy(int num) {
try {
IndexSearcher searcher = getSearcher();
//查询名字为mikes的,但是实际上索引里面域name里面真正的名字是mike
FuzzyQuery query = new FuzzyQuery(new Term("name", "mikes"),1);
TopDocs tds = searcher.search(query, num);
System.out.println("一共查询了:" + tds.totalHits + "条记录");
for (final ScoreDoc sd : tds.scoreDocs) {
Document doc = searcher.doc(sd.doc);
System.out.println("我有" + doc.get("money") + "块,名字为:" + doc.get("name")
+ ",邮箱为[" + doc.get("email") + "] " + ",内容为: " + "[" + doc.get("content") + "]");
}
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void testSearchByFuzzy() {
LuceneQueryAll luceneQueryAll = new LuceneQueryAll();
luceneQueryAll.searchByFuzzy(10);
}
运行上面的测试类,运行结果如下:
一共查询了:1条记录
我有500块,名字为:mike,邮箱为[ee@travelsky.com] ,内容为: [I like football and I like basketball too]
Lucene还提供了很多的查询对象,比如通配符查询,根据范围查询,这里不依依介绍,想深入了解的,可以看Lucene的官网文档,都有相应的demo。
原文:http://090508tanjie.iteye.com/blog/2289712