使用单个字符查询lucene索引,例如姓名首字母

时间:2016-11-10 13:40:15

标签: java indexing lucene hibernate-search

我有一个公司和人员数据库,我想用Lucene(通过Hibernate Search)查询。搜索功能实现为自动完成样式查找,其中网页将根据用户类型建议匹配。

部分公司和人员使用首字母标识,例如

  • G& H CIVIL ENGINEERING
  • J G VAN DER MERWE

我希望用户在键入几个字母后开始获得匹配,但逐渐完善搜索,因为他们添加了更多文本(可能包括空格)。我正在查询几个不同的领域,例如使用单个术语的名称,商品名称,ID号码,电话号码等,以便用户可以键入部分名称,ID号,商号或单元号。

但是,我在设置索引和查询时遇到问题,因此像G & H这样的术语会与文档匹配。使用像CIVIL这样的术语,会有很多匹配。但是,中间有空格的单个字符不匹配任何内容。

以下测试在最后一行失败。我不确定分析仪,标记器,滤波器和放大器的组合。我应该使用的查询。

@Test
public void testSearching() throws Exception {
    Analyzer analyzer = new ReusableAnalyzerBase() {
        @Override
        protected TokenStreamComponents createComponents(String fieldName, Reader reader) {
            StandardTokenizer tokenizer = new StandardTokenizer(Version.LUCENE_36, reader);
            LowerCaseFilter lowerCaseFilter = new LowerCaseFilter(Version.LUCENE_36, tokenizer);
            NGramTokenFilter filter = new NGramTokenFilter(lowerCaseFilter, 3, 20);
            return new TokenStreamComponents(tokenizer, filter);
        }
    };
    Directory ramDirectory = new RAMDirectory();

    IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_36, analyzer);
    IndexWriter w = new IndexWriter(ramDirectory, config);

    Document doc = new Document();
    doc.add(new Field("id", "819", Field.Store.YES, Field.Index.NOT_ANALYZED));
    doc.add(new Field("particulars.registeredName", "G & H CIVIL ENGINEERING", Field.Store.NO, Field.Index.ANALYZED));

    w.addDocument(doc);
    w.close();

    // search
    int numberOfHits = 200;
    TopScoreDocCollector collector = TopScoreDocCollector.create(numberOfHits, true);
    IndexSearcher searcher = new IndexSearcher(IndexReader.open(ramDirectory));

    PhraseQuery q = new PhraseQuery();
    q.add(new Term("particulars.registeredName", "civil"));
    searcher.search(q, collector);
    ScoreDoc[] hits = collector.topDocs().scoreDocs;
    assertThat(hits.length, greaterThan(0));

    PhraseQuery phraseQuery = new PhraseQuery();
    phraseQuery.add(new Term("particulars.registeredName", "g & h"));
    searcher.search(q, collector);
    hits = collector.topDocs().scoreDocs;
    assertThat(hits.length, greaterThan(0)); // this fails - no matches

我是Lucene的新手 - 任何指针都会受到赞赏。

1 个答案:

答案 0 :(得分:0)

您的特定问题可能与您重新使用收集器的事实有关,该收集器是有状态的,仅供一次性使用。在第二个查询中使用新的收集器应该可以解决问题。

,请注意,使用Hibernate Search时,您不应该多接触Lucene内部:Hibernate Search会在索引时自动从您的实体派生Lucene文档,并构建索引读取器和收集时根据需要查询。如果您还不熟悉Lucene / Hibernate Search,我强烈建议您不要直接使用Lucene:Lucene功能强大,但不是一个易于使用的工具。

这意味着使用带注释(或编程映射)的实体,而不是手动构建文档。请参阅the documentation,特别是section about entity mappingsection about analysis

此外,查询时,您可以使用the Hibernate Search DSL。它可能比构建原始Lucene查询更容易。在构建查询后,您也可以轻松地将Hibernate Search问retrieve the results