使用nGram进行休眠搜索|如何指示nGram在搜索过程中不赚钱

时间:2019-05-10 07:18:40

标签: elasticsearch hibernate-search

我的分析器定义如下

@AnalyzerDefs({
@AnalyzerDef(name = "ngram",
            tokenizer = @TokenizerDef(factory = KeywordTokenizerFactory.class),
            filters = {
                    //@TokenFilterDef(factory = StandardFilterFactory.class),
                    @TokenFilterDef(factory = LowerCaseFilterFactory.class),
                    @TokenFilterDef(factory = NGramFilterFactory.class, params = {
                            @Parameter(name = "minGramSize", value = "3"),
                            @Parameter(name = "maxGramSize", value = "255") }) }),
//-----------------------------------------------------------------------
    @AnalyzerDef(name = "ngram_query",
            tokenizer = @TokenizerDef(factory = KeywordTokenizerFactory.class),
            filters = {
                    //@TokenFilterDef(factory = StandardFilterFactory.class),
                    @TokenFilterDef(factory = LowerCaseFilterFactory.class)
                    }) 
})

@Analyzer(definition = "ngram")
public class EPCAsset extends Asset {
    @Field
    private String obturatorMaterial;

}

它在索引时间内完美地构成了n克项的向量。但这也会在搜索期间产生n-gram搜索查询。

我想要的是一种搜索查询,它使用n-gram索引进行搜索而又不将搜索词分解成g的方式。

注意:我必须在这里使用n-gram,因为要求是在文本中的任何位置进行搜索。开始或中间。所以我无法选择edge-n-gram。

示例: 输入要作为索引 ICQ 234

的数据

然后在索引时间内其项向量为

    "234"
    " 23"
    " 234"
    "cq "
    "cq 2"
    "cq 23"
    "cq 234"
    "icq"
    "icq "
    "icq 2"
    "icq 23"
    "icq 234"
    "q 2"
    "q 23"
    "q 234"

现在,当我搜索 icq 时,它可以完美运行。但它也适用于 icqabc ,因为在搜索期间它会进行n克的搜索查询。因此,有一种方法可以在搜索期间不破坏搜索词,而是使用n-gram索引进行搜索。

这是我的搜索查询建筑物

FullTextEntityManager fullTextEntityManager = Search
            .getFullTextEntityManager(entityManager);

QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder()
            .forEntity(entityClass).get();
Query query = qb.phrase().onField("obturatorMaterial").sentence("icqabc").createQuery();
FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(query,
            entityClass);
fullTextQuery.getResultList()

我正在使用弹性搜索作为Hibernate搜索的后端。

编辑: 我还按照@yrodiere的答案应用了查询时间分析器,但它给了我错误。

QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder()
            .forEntity(entityClass).overridesForField("obturatorMaterial","ngram_query").get();
  

org.hibernate.search.exception.SearchException:HSEARCH000353:未知分析器:“ ngram_query”。确保已定义此分析器。

编辑

根据此链接overriderForField when using elasticsearch backed hibernate search

我现在可以定义一个查询时间2nd分析器,它解决了这个问题。

2 个答案:

答案 0 :(得分:1)

您要么需要使用search time analyzer,要么很可能是搜索期间的关键字分析器。或需要使用term查询而不是match查询,这意味着对其进行分析意味着它使用的分析器使用的索引时间相同。

详细了解term querymatch query,以了解更多信息。

编辑:-https://www.elastic.co/guide/en/elasticsearch/reference/current/search-analyzer.html明确讨论了在 edgeNGram令牌生成器自动完成功能的情况下 search_analyzer 的使用搜索,这正是您的用例。

答案 1 :(得分:1)

首先,您应该仔细检查一个ngram过滤器是否确实是您想要的。我之所以这样说是因为ngram分析器通常同时用于索引和查询,因此它提供了模糊匹配。这就是分析仪的重点。

当用户键入cq 2时,您真的需要匹配吗?是否有意义?在实现自动完成功能时,人们通常更喜欢只将包含开始的单词与用户输入进行匹配,因此i会匹配,icicq也会匹配,但cq 2除外。如果这正是您想要的,则应查看“ edge_ngram”过滤器。它可以改善匹配的相关性,也不需要太多的磁盘空间。

现在,即使使用“ edge_ngram”过滤器,您也需要在查询时禁用ngram。在Hibernate Search中,这是通过“覆盖”分析器来完成的。

  1. 首先,定义第二个分析器,该分析器与您在索引编制过程中使用的分析器相同,但没有“ ngram”或​​“ edge_ngram”过滤器。将其命名为“ ngram_query”。
  2. 然后,使用它来创建查询构建器:

    QueryBuilder queryBuilder = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(EPCAsset.class)
        .overridesForField( "obturatorMaterial", "ngram_query" )
        .get();
    
  3. 使用查询生成器照常创建查询。

请注意,如果您依靠Hibernate Search将索引架构和分析器推送到Elasticsearch,则必须使用hack才能推送仅查询分析器:默认情况下,仅实际使用的分析器在索引期间被推送。参见https://discourse.hibernate.org/t/cannot-find-the-overridden-analyzer-when-using-overridesforfield/1043/4