Lucene 的搜索

       Lucene 的搜索
 
以上完成了索引的建立和一些关于索引的知识,但是光有索引是不行的,我们真正要做的检索,这才是我们的关键。现在我们看看 lucene 的检索吧。
认识检索从检索的工具开始吧! IndexSearcher 类是 lucene 用于检索的工具类,我们在检索之前要得到这个类的实例。
第一步我们看以下代码:
IndexSearcher searcher = new IndexSearcher("c://index");
创建 IndexSearcher 实例需要告诉 lucene 索引的位置,就是你 IndexWrite 的文件路径。
Query query = null;
Hits hits = null;
query = QueryParser.parse(key1, "name", new StandardAnalyzer());
hits = searcher.search(query);
if (hits != null) {
           if (hits.length() == 0) {
              System.out.println(" 没有找到任何结果 ");
           } else {
              System.out.print(" 找到 ");
              for (int i = 0; i < hits.length(); i++) {
                  Document d = hits.doc(i);
                  String dname = d.get("title");
                  System.out.print(dname + "   " );
              }
           }
       }
}
以上就是一个完整的检索过程,这里我们看见了个 Query Hits ,这两个类就是比较关键的了,我们先从检索结果的 Hits 类说起。
我们使用 Hits 经常使用的几个方法有:
length() :  返回搜索结果的总数量。
Doc(int n) : 放回第 n 个文档。
Id(int n) : 返回第 n 个文档的内部编号。
Sorce(int n) : 返回第 n 个文档的得分。
看见这个 Sorce(int n) 这个方法,是不是就可以联想到搜索引擎的排序问题呢,像百度的推广是怎么做出来的呢 , 可想而知吧,那就说明必定存在一中方法可以动态的改变某片文档的得分。对了, lucene 中可以使用 Document setBoost 方法可以改变当前文档的 boost 因子。
下面我们看看:
Document doc1 = new Document();
doc1.add(Field.Text("contents", "word1 word"));
doc1.add(Field.Keyword("path", "path//document1.txt"));
 doc1.setBoost(1.0f);
 
  这样我们就在改变了篇文档的评分了,当 boost 的值越大它的分值就越高,其出现的位置就越靠前。
让我们再来看看 lucene 为我们提供的各种 Query 吧。
第一、   按词条搜索 TermQuery
query = new TermQuery(new Term("name","word1"));
hits = searcher.search(query);
这样就可以把 field name 的所有包含 word1 的文档检索出来了。
第二、  “与或”搜索 BooleanQuery
它实际是一个组合 query 看看下面的代码:
query1 = new TermQuery(new Term("name","word1"));
query2 = new TermQuery(new Term("name","word2"));
query = new BooleanQuery();
query.add(query1, false, false);
query.add(query2, false, false);
hits = searcher.search(query);
看看 booleanQuery 的用法吧:
true & true : 表明当前加入的字句是必须要满足的。相当于逻辑与。
false & true : 表明当前加入的字句是不可一被满足的, 相当于逻辑非。
false & false : 表明当前加入的字句是可选的,相当于逻辑或。
true & true : 错误的情况。
Lucene 可以最多支持连续 1024 query 的组合。
第三、  在某一范围内搜索 RangeQuery
IndexSearcher searcher = new IndexSearcher("c://index");
     Term beginTime = new Term("time","200001");
     Term endTime = new Term("time","200005");
     Hits hits = null;
     RangeQuery query = null;
     query = new RangeQuery(beginTime, endTime, false);
     hits = searcher.search(query);
RangeQuery 的构造函数的参数分别代表起始、结束、是否包括边界。这样我们就可以按照要求检索了。
第四、  使用前缀检索 PrefixQuery
这个检索的机制有点类似于 indexOf() 从前缀查找。这个常在英文中使用,中文中就很少使用了。代码如下:
IndexSearcher searcher = new IndexSearcher("c://index");
       Term pre1 = new Term("name", "Da");
       query = new PrefixQuery(pre1);
       hits = searcher.search(query);
第五、  多关键字的搜索 PhraseQuery
可以多个关键字同时查询。使用如下:
query = new PhraseQuery();
       query.add(word1);
       query.add(word2);
       query.setSlop(0);
       hits = searcher.search(query);
       printResult(hits, "'david' 与 'mary' 紧紧相隔的 Document");
       query.setSlop(2);
       hits = searcher.search(query);
       printResult(hits, "'david' 与 'mary' 中相隔两个词的短语 ");
    这里我们要注意 query.setSlop(); 这个方法的含义。
query.setSlop(0);  紧紧相连 (这个的条件比较苛刻)
query.setSlop(2);  相隔
第六、  使用短语缀搜索 PharsePrefixQuery
使用 PharsePrefixQuery 可以很容易的实现相关短语的检索功能。
实例:
query = new PhrasePrefixQuery();
       // 加入可能的所有不确定的词
Term word1 = new Term("content", "david");
       Term word2 = new Term("content", "mary");
       Term word3 = new Term("content", "smith");
       Term word4 = new Term("content", "robert");
       query.add(new Term[]{word1, word2});
       // 加入确定的词
       query.add(word4);
       query.setSlop(2);
       hits = searcher.search(query);
       printResult(hits, " 存在短语 'david robert' 或 'mary robert' 的文档 ");
第七、  相近词语的搜索 fuzzyQuery
可以通俗的说它是一种模糊查询。
 
 
实例:
Term word1 = new Term("content", "david");
       Hits hits = null;
       FuzzyQuery query = null;
       query = new FuzzyQuery(word1);
       hits = searcher.search(query);
       printResult(hits," 与 'david' 相似的词 ");
第八、  使用通配符搜索 WildcardQuery
实例:
IndexSearcher searcher = new IndexSearcher("c://index");
       Term word1 = new Term("content", "*ever");
       Term word2 = new Term("content", "wh?ever");
       Term word3 = new Term("content", "h??ever");
       Term word4 = new Term("content", "ever*");
       WildcardQuery query = null;
       Hits hits = null;
       query = new WildcardQuery(word1);
       hits = searcher.search(query);
       printResult(hits, "*ever");
       query = new WildcardQuery(word2);
       hits = searcher.search(query);
       printResult(hits, "wh?ever");     
       query = new WildcardQuery(word3);
       hits = searcher.search(query);
       printResult(hits, "h??ever");     
       query = new WildcardQuery(word4);
       hits = searcher.search(query);
       printResult(hits, "ever*");
    由上可以看出通配符?代便 1 个字符, * 代表 0 到多个字符。
Lucene 现在支持以上八中的搜索方式,我们可以根据需要选择适合自己的搜索方式。当然上面提供的一些可能对英文还是比较有效,中文就不可取了,所以我们开始想想百度,我们只在一个输入框中搜索结果。有了这个疑问我们揭开下一章的讨论吧!
查询字符串的解析:这个就是我们经常在一个输入框中输入我们要检索的文字,交给搜索引擎去帮我们分词。
QueryParser 类就是对查询字符串的解析类。
看看它的用法:
 
query = QueryParser.parse(key1, "name", new StandardAnalyzer());
hits = searcher.search(query);
它直接返回一个 Query 对象。需要传入的参数分别是:
用户需要查询的字符串、需要检索的对应字段名称、采用的分词类。
Analyzer analyzer = new CJKAnalyzer();
String[] fields = {"filename", "content"};
Query query = MultiFieldQueryParser.parse(searchword, fields, analyzer);
Hits hits = searcher.search(query);
QueryParser 的“与” “或”:
QueryParser 之间默认是或,我们想改变为与的话加入以下代码:
QueryParser.setOperator(QueryParser.DEFAULT_OPERATOR_AND);
就可以了。
5          高级搜索技巧
前面我们已经介绍了一般情况下 lucene 的使用技巧,现在我们探讨一下高级搜索的技巧吧!
1、 对搜索结果进行排序:
1) 使用 sort 类排序:
    Sort sort = new Sort();
        hits = searcher.search(query,sort);
这种方式是使用默认的 sort 排序方式进行排序。默认的 sort 排序是按照相关度进行排序。即通过 luence 的评分机制进行排序。
2) 对某一字段进行排序
       Sort sort = new Sort( “ content ” );
     hits = searcher.search(query,sort);
3) 对多个字段进行排序
Sort sort = new Sort(new SortField[]{new SortField("title"),new SortField("contents")});
hits = searcher.search(query,sort);
2、 多域搜索和多索引搜索:
在使用 luecene 时,如果查询的只是某些 terms ,而不关心这些词条到时来自那个字段中时。这时可以使用 MultiFieldQueryParser 类。这个用于用户搜索含有某个关键字是否存在在字段中,他们之间的关系使用 OR 连接。即不管存在在哪一个字段都会显示显示出来。
使用 MultiSearcher 可以满足同时多索引的搜索需求。
Searcher[] searchers = new Searcher[2];
searchers[0] = new IndexSearcher(indexStoreB);
searchers[1] = new IndexSearcher(indexStoreA);
        // 创建一个多索引检索器
Searcher mSearcher = new MultiSearcher(searchers);
3、     对搜索结果进行过滤:
1)    对时间进行过滤
         通常情况下我们对搜索结果要进行过滤显示,即只显示过滤后的结果。
doc.add(Field.Keyword("datefield", DateField.timeToString(now - 1000)));
DateFilter df1 = DateFilter.Before("datefield", now);
2)        查询过滤器
通过查询过滤器可以过滤一部分的信息。
Filter filter = new Filter()
        {
       public BitSet bits (IndexReader reader) throws IOException
          {
            BitSet bitset = new BitSet(5);
            bitset.set (1);
            bitset.set (3);
            return bitset;
          }
        };
        // 生成带有过滤器的查询对象
        Query filteredquery = new FilteredQuery (query, filter);
       // 返回检索结果
        Hits hits = searcher.search (filteredquery);
 
这样我们就可以使用自己定义的过滤方式去过滤信息了。
3)    带缓存的过滤器:
使用待缓存的过滤器我们可以重用过滤功能,如下:
MockFilter filter = new MockFilter();
 CachingWrapperFilter cacher = new CachingWrapperFilter(filter);
        cacher.bits(reader);
以上介绍完了现在学习 luence ,没有太详细的介绍它的实现,因为它对于我们来说是一个工具,既然是工具我们就要会用就可以了。

你可能感兴趣的:(Lucene 的搜索)