Lucene06---查询
前面总结了很多Lucene上的东西,建立索引、高亮等等这些都是为了查询做准备和服务的,下面我们来说说查询,我们知道Lucene的主要功能就是查询功能,所以Lucene里的查询做的非常强大,可以有各种各样的查询。
org.apache.lucene.search.Query包下的Query类下有需要查询对象,这里我们说其中几个比较重要的:
TermQuery:关键字查询
TermRangeQuery:范围查询
WildcardQuery:通配符查询
PhraseQuery:短语查询
BooleanQuery:Boolean查询(最重要的)
FirstLucene04SearchByQuery.Java:
package com.iflytek.lucene; import java.io.File; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.queryParser.MultiFieldQueryParser; import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.Filter; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TopDocs; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.store.RAMDirectory; import org.apache.lucene.util.Version; /** * @author xudongwang 2012-2-10 * * Email:[email protected] */ public class FirstLucene04SearchByQuery { /** * 源文件路径 */ private String filePath01 = "F:\\Workspaces\\workspaceSE\\BlogDemo\\luceneDatasource\\HelloLucene01.txt"; private String filePath02 = "F:\\Workspaces\\workspaceSE\\BlogDemo\\luceneDatasource\\HelloLucene04.txt"; /** * 索引路径 */ private String indexPath = "F:\\Workspaces\\workspaceSE\\BlogDemo\\luceneIndex"; /** * 分词器,这里我们使用默认的分词器,标准分析器(好几个,但对中文的支持都不好) */ private Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_35); private Directory ramDir = null; /** * 搜索 * * @param queryStr * 搜索的关键词 * @throws Exception */ public void search(String queryStr) throws Exception { // 1、把要搜索的文本解析为Query对象 String[] fields = { "name", "content" }; QueryParser queryParser = new MultiFieldQueryParser(Version.LUCENE_35, fields, analyzer); Query query = queryParser.parse(queryStr); search(query); } /** * 搜索 * * @param query * Query对象 * @throws Exception */ public void search(Query query) throws Exception { // 2、进行查询 IndexReader indexReader = IndexReader.open(ramDir); IndexSearcher indexSearcher = new IndexSearcher(indexReader); Filter filter = null; TopDocs topDocs = indexSearcher.search(query, filter, 10000); System.out.println("总共有【" + topDocs.totalHits + "】条匹配的结果");// 注意这里的匹配结果是指文档的个数,而不是文档中包含搜索结果的个数 // 3、取出数据,并打印结果 for (ScoreDoc scoreDoc : topDocs.scoreDocs) { int docSn = scoreDoc.doc;// 文档内部编号 Document document = indexSearcher.doc(docSn);// 根据文档编号取出相应的文档 File2Document.printDocumentInfo(document);// 打印出文档信息 } } /** * 优化创建索引,将索引存在在内存和磁盘配合使用 * * @throws Exception */ public void createIndexByYouHua() throws Exception { File indexFile = new File(indexPath); Directory fsDir = FSDirectory.open(indexFile); // 1、启动时,将磁盘中的索引读取到内存中 ramDir = new RAMDirectory(fsDir); IndexWriterConfig ramConf = new IndexWriterConfig(Version.LUCENE_35, analyzer); // 运行程序时操作内存中的索引 IndexWriter ramIndexWriter = new IndexWriter(ramDir, ramConf); Document document = File2Document.file2Document(filePath01); Document document2 = File2Document.file2Document(filePath02); ramIndexWriter.addDocument(document); ramIndexWriter.addDocument(document2); ramIndexWriter.close(); // 2、退出时将内存中的索引保存到磁盘中 IndexWriterConfig fsConf = new IndexWriterConfig(Version.LUCENE_35, analyzer); IndexWriter fsIndexWriter = new IndexWriter(fsDir, fsConf); fsIndexWriter.addIndexes(ramDir);// 把另外几个索引库中的所有索引数据合并到当前的索引库中 fsIndexWriter.commit(); //fsIndexWriter.optimize();// 对索引文件进行优化,从而减少IO操作 fsIndexWriter.forceMerge(1); fsIndexWriter.close(); } public static void main(String[] args) throws Exception { FirstLucene04SearchByQuery lucene = new FirstLucene04SearchByQuery(); //lucene.createIndexByYouHua(); lucene.search("iteye"); } }
关键词查询(TermQuery):
/** * 关键字查询 * * @throws Exception */ public void testTermQuery() throws Exception { Term term = new Term("content", "iteye"); // 关键字查询,注意关键词中没有大写字符,全是小写字符 Query query = new TermQuery(term); System.out.println("对应的查询字符串:"+query); byQuery.createIndexByYouHua(); byQuery.search(query); }
运行结果:
总共有【2】条匹配的结果 name -->HelloLucene01.txt
path -->F:\Workspaces\workspaceSE\BlogDemo\luceneDatasource\HelloLucene01.txt size -->84 name -->HelloLucene04.txt
path -->F:\Workspaces\workspaceSE\BlogDemo\luceneDatasource\HelloLucene04.txt size -->738 |
范围查询(TermRangeQuery):
/** * 范围查询 * * @throws Exception */ public void testTermRangeQuery() throws Exception { // true表示包含边界 Query query = new TermRangeQuery("size",200,900, true, true); byQuery.createIndexByYouHua(); byQuery.search(query); }
运行结果:
总共有【1】条匹配的结果 name -->HelloLucene04.txt
path -->F:\Workspaces\workspaceSE\BlogDemo\luceneDatasource\HelloLucene04.txt size -->738 |
但是上面需要注意的是如果上面的范围是100-1000,则就不会有结果,这是为什么呢?
大家需要注意,这里100和1000字符串排序谁大?应该是100大,因为100的ANSIC大,所以这里它是按照字符串进行排序的,因为它在储存的时候里面全部都是字符串。这时怎么办呢?解决方法就是让索引的时候是相同的宽度,搜索的时候也是相同的宽度。
将Test里的方法改为:
public void testTermRangeQuery() throws Exception { // true表示包含边界 Query query = new TermRangeQuery("size", NumberTools.longToString(100), NumberTools.longToString(1000), true, true); byQuery.createIndexByYouHua(); byQuery.search(query); }
同时在建立索引的地方,File2Document.java中,需要将
document.add(new Field("size", String.valueOf(file.length()), Store.YES, Index.NOT_ANALYZED));
改为:
document.add(new Field("size", NumberTools.longToString(file.length()), Store.YES, Index.NOT_ANALYZED));
但是这里的方法提示过时了,在3.5中我还没找到类似的方法,知道的可以告诉我一下。
通配符查询(WildcardQuery):
/** * 通配符查询 * * '?'代表一个字符 * * '*'代表0个或多个字符 * * @throws Exception */ public void testWildcardQuery() throws Exception { // Term term = new Term("content", "itey?"); Term term = new Term("content", "ite*"); Query query = new WildcardQuery(term); byQuery.createIndexByYouHua(); byQuery.search(query); }
运行结果:
总共有【2】条匹配的结果 name -->HelloLucene01.txt
path -->F:\Workspaces\workspaceSE\BlogDemo\luceneDatasource\HelloLucene01.txt size -->84 name -->HelloLucene04.txt
path -->F:\Workspaces\workspaceSE\BlogDemo\luceneDatasource\HelloLucene04.txt size -->738 |
短语查询(PhraseQuery):
/** * 短语查询 * @throws Exception */ public void testPhraseQuery() throws Exception{ PhraseQuery phraseQuery = new PhraseQuery(); //这里的1和3是相对的位置 phraseQuery.add(new Term("content","iteye"),1); phraseQuery.add(new Term("content","address"),3); /** * phraseQuery.add(new Term("content","iteye")); phraseQuery.add(new Term("content","address")); //设置上面的两个词之间最多能隔几个词 phraseQuery.setSlop(2); */ byQuery.createIndexByYouHua(); byQuery.search(phraseQuery); }
运行结果:
总共有【1】条匹配的结果 name -->HelloLucene01.txt
path -->F:\Workspaces\workspaceSE\BlogDemo\luceneDatasource\HelloLucene01.txt size -->84 |
Boolean查询(BooleanQuery):
/** * Boolean查询 * * @throws Exception */ public void testBooleanQuery() throws Exception{ //条件一 短语查询 PhraseQuery phraseQuery = new PhraseQuery(); phraseQuery.add(new Term("content","iteye"),1); phraseQuery.add(new Term("content","address"),3); //条件二 范围查询 Query query = new TermRangeQuery("size", NumberTools.longToString(100), NumberTools.longToString(1000), true, true); BooleanQuery booleanQuery = new BooleanQuery(); //条件一必须出现,条件二可能出现 booleanQuery.add(phraseQuery, Occur.MUST); booleanQuery.add(query, Occur.SHOULD); byQuery.createIndexByYouHua(); byQuery.search(booleanQuery); }
运行结果:
总共有【1】条匹配的结果 name -->HelloLucene01.txt
path -->F:\Workspaces\workspaceSE\BlogDemo\luceneDatasource\HelloLucene01.txt size -->84 |
说明:
Occur用于表示布尔查询子句关系,包括:
Occur.MUST、Occur.MUST_NOT、Occur.SHOULD;
1、MUST和MUST,取得两个查询子句的交集;
2、MUST和MUST_NOT,包含MUST并且查询结果中不包含MUST_NOT的检索结果;
3、SHOULD和SHOULD,表示“或”关系,最终检索结果为所有检索子句的并集;
使用时注意:
1、MUST和SHOULD:此时SHOULD无意义,结果为MUST子句的检索结果;
2、MUST_NOT和MUST_NOT,无意义,检索无结果;
3、MUST_NOT和SHOULD,此时SHOULD相当于MUST,结果同MUST和MUST_NOT;
4、单独使用SHOULD,结果相当于MUST;
5、单独使用MUST_NOT,无意义,检索无结果;