【问题标题】:Hibernate search on prefixes前缀的休眠搜索
【发布时间】:2016-07-08 00:39:07
【问题描述】:

现在,我已经成功配置了一个基本的 Hibernate 搜索索引,以便能够在我的 JPA 实体的各个字段中搜索完整的单词:

@Entity
@Indexed
class Talk {
    @Field String title
    @Field String summary
}

我的查询看起来像这样:

List<Talk> search(String text) {
    FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager)
    QueryBuilder queryBuilder = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Talk).get()
    Query query = queryBuilder
            .keyword()
            .onFields("title", "summary")
            .matching(text)
            .createQuery()
    FullTextQuery jpaQuery = fullTextEntityManager.createFullTextQuery(query, Talk)
    return jpaQuery.getResultList()
}

现在我想微调这个设置,这样当我搜索“test”时,它仍然可以找到标题或摘要包含“test”的谈话,即使是另一个单词的前缀。因此,标题为“单元测试”或摘要包含“睾丸”的演讲仍应出现在搜索结果中,而不仅仅是标题或摘要包含“测试”作为完整单词的演讲。

我试图查看文档,但我不知道是否应该对我的实体的索引方式进行更改,或者它是否与查询有关。请注意,我想做类似以下的事情,但是很难搜索多个字段:

 Query query = queryBuilder
            .keyword().wildcard()
            .onField("title")
            .matching(text + "*")
            .createQuery()

编辑: 根据 Hardy 的回答,我像这样配置了我的实体:

@Indexed
@Entity
@AnalyzerDefs([
@AnalyzerDef(name = "ngram",
        tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
        filters = [
            @TokenFilterDef(factory = LowerCaseFilterFactory.class),
            @TokenFilterDef(factory = NGramFilterFactory.class,
                    params = [
                        @Parameter(name = "minGramSize",value = "3"),
                        @Parameter(name = "maxGramSize",value = "3")
                    ])
        ])
])
class Talk {
    @Field(analyzer=@Analyzer(definition="ngram")) String title
    @Field(analyzer=@Analyzer(definition="ngram")) String summary
}

由于该配置,当我搜索“arti”时,我会看到标题或摘要包含“arti”是(艺术家、手工等)子词的单词。不幸的是,在那之后我还得到了会谈,其中标题或摘要包含包含我的搜索词的子词(艺术、放屁等)的词。可能有一些微调可以消除这些,但至少我现在能更快地得到结果,而且它们的顺序很合理。

【问题讨论】:

    标签: java hibernate jpa hibernate-search


    【解决方案1】:

    您应该使用NgramEdgeNGram 过滤器作为您在答案中正确指出的索引。但是您应该按照 lucene 文档中的建议对查询使用不同的分析器(请参阅search_analyzer): https://www.elastic.co/guide/en/elasticsearch/guide/current/_index_time_search_as_you_type.html

    这样,您的搜索查询不会被标记为 ngram,您的结果将更像 SQL 中的 %text%text%

    很遗憾,由于未知原因,Hibernate Search 目前不支持字段上的search_analyzer 规范。您只能使用特定的分析器进行索引,这也将用于搜索查询分析。

    我打算自己实现这个功能。

    编辑:

    您可以像这样指定搜索时间分析器 (search_analyzer):

    List<Talk> search(String text) {
        FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager)
        EntityContext entityContext = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Talk);
    
        entityContext.overridesForField("myField", "myNamedAnalyzerDef");
    
        QueryBuilder queryBuilder = ec.get()
        Query query = queryBuilder
                .keyword()
                .onFields("title", "summary")
                .matching(text)
                .createQuery()
        FullTextQuery jpaQuery = fullTextEntityManager.createFullTextQuery(query, Talk)
        return jpaQuery.getResultList()
    }
    

    我已经使用这种技术有效地模拟了 Lucene search_analyzer 属性。

    【讨论】:

      【解决方案2】:

      在 Lucene 4.9 版中,我为此使用了EnglishAnalyzer。我认为这是 SnowballAnalyzer 的仅英文实现,但不是 100% 确定的。我用它来创建和搜索索引。使用它没有什么特别需要的。

      Analyzer analyzer = new EnglishAnalyzer(Version.LUCENE_4_9);
      IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_4_9, analyzer);
      

      analyzer = new EnglishAnalyzer(Version.LUCENE_4_9);
      parser = new StandardQueryParser(analyzer);
      

      您可以在Guided Code Search 看到它的实际应用。这完全在 Lucene 上运行。

      Lucene 可以集成到 Hibernate 搜索中,但我自己还没有尝试过这样做。我似乎会很强大,但我不知道:见Apache Lucene™ Integration

      我还读到了 lucene 可以修补到 SQL 引擎中,但我也没有尝试过。示例:Indexing Databases with Lucene

      【讨论】:

        【解决方案3】:

        您可以在这里做很多事情。在索引期间通过适当的分析可以做很多事情。

        例如,您想应用适合您的语言的词干分析器。对于英语,这通常是 Snowball 词干分析器。其想法是,在索引期间,所有单词都被简化为它们的词干,例如 testingtested 到 _test。这会让你走得更远。

        您可以研究的另一件事是 ngramm 索引。根据您的描述,您也想在不相关的单词中找到匹配项。这里的想法是索引每个单词的“子词”,以便以后可以找到它们。

        关于您想查看 Hibernate Search 文档的named analyzers部分的分析器。这里的关键是@AnalyzerDef注解。

        在查询方面,您还可以应用一些“技巧”。实际上,您可以使用通配符查询,但是,如果您使用的是 Hibernate Search 查询 DSL,则不能使用 keyword 查询,但您需要使用 wildcard 查询。再次检查 Hibernate Search 文档。

        【讨论】:

        • 我配置了 Ngram 分析器,效果更好。不幸的是,它似乎也加载了搜索词本身的子词。因此,如果我搜索“arti”,它会显示包含“arti”作为子词的结果,然后显示包含“art”和“rti”的结果。所以我现在得到的结果太多了,但至少它们的顺序是合理的。
        猜你喜欢
        • 2011-11-17
        • 2021-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-23
        • 2020-09-18
        • 2015-07-25
        相关资源
        最近更新 更多