gpt4 book ai didi

java - 具有自动完成和模糊功能的 Hibernate 搜索

转载 作者:行者123 更新时间:2023-12-02 08:43:06 28 4
gpt4 key购买 nike

我正在尝试创建 StingUtils 的 Hibernate 搜索表示 containsIgnoreCase()方法与模糊搜索匹配相结合

假设用户写入字母“p”,他们将获得包含字母“p”的所有匹配项(无论该字母位于各个匹配项的开头、中间还是末尾)。

当它们形成“Peter”等单词时,它们也应该收到模糊匹配,例如“Petar”、“Petaer”和“Peder”。

我正在使用出色的答案 here 中提供的自定义查询和索引分析器,因为我需要 minGramSize 为 1 以允许自动完成功能,同时我还期望用空格分隔的多词用户输入,例如“EUR Account of Peter”,这可以是在不同的情况下(较低或较高)。

因此,用户应该能够键入“AND”并接收上述示例作为匹配项。

目前,我正在使用以下查询:

  org.apache.lucene.search.Query fuzzySearchByName = qb.keyword().fuzzy()
.withEditDistanceUpTo(1).onField("name")
.matching(userInput).createQuery();
booleanQuery.add(fuzzySearchByName, BooleanClause.Occur.MUST);

但是,完全匹配案例不会出现在搜索结果中:

如果我们输入“petar”,我们会得到以下结果:

  1. Petarr(非精确匹配)
  2. Petaer(非完全匹配)

... 4.PETAR(完全匹配)

同样适用于用户输入“peter”,其中第一个结果是“Petero”,第二个结果是“Peter”(第二个结果应该是第一个结果)。

我还需要仅包含多词查询的精确匹配 - 例如如果我开始写“Account for...”,我希望所有匹配结果都包含短语“Account for”,并最终包含基于该短语的模糊相关术语短语(与前面展示的 containsIgnoreCase() 方法基本相同,只是尝试添加模糊支持)

但是我猜这与 minGramSize 为 1 和 WhitespaceTokenizerFactory 是矛盾的?

最佳答案

However, exact match cases do not receive presendence in the search results:

只需使用两个查询而不是一个:

编辑:您还需要为自动完成和“精确”匹配设置两个单独的字段;请参阅底部的我的编辑。

  org.apache.lucene.search.Query exactSearchByName = qb.keyword().onField("name")
.matching(userInput).createQuery();
org.apache.lucene.search.Query fuzzySearchByName = qb.keyword().fuzzy()
.withEditDistanceUpTo(1).onField("name")
.matching(userInput).createQuery();
org.apache.lucene.search.Query searchByName = qb.boolean().should(exactSearchByName).should(fuzzySearchByName).createQuery();
booleanQuery.add(searchByName, BooleanClause.Occur.MUST);

这将匹配包含完全用户输入的文档,因此这将匹配与您的示例相同的文档。但是,完全包含用户输入的文档将匹配两个查询,而仅包含相似内容的文档将仅匹配模糊查询。因此,完全匹配的分数会更高,并且在结果列表中的排名也会更高。

如果精确匹配不够高,请尝试向 exactSearchByName 查询添加提升:

  org.apache.lucene.search.Query exactSearchByName = qb.keyword().onField("name")
.matching(userInput)
.boostedTo(4.0f)
.createQuery();

I guess however that this contradics with the minGramSize of 1 and the WhitespaceTokenizerFactory?

如果您想要匹配包含用户输入中出现的任何单词(但不一定是所有单词)的文档,并将包含更多单词的文档放在结果列表中更高的位置,请按照我上面的说明进行操作。

如果您想要匹配包含完全相同顺序的所有单词的文档,请使用 KeywordTokenizerFactory(即不进行标记)。

如果您想匹配包含任意顺序的所有单词的文档,那么...这不太明显。 Hibernate Search ( yet ) 不支持这一点,因此您基本上必须自己构建查询。我已经见过的一种黑客行为是这样的:

Analyzer analyzer = fullTextSession.getSearchFactory().getAnalyzer( "myAnalyzer" );

QueryParser queryParser = new QueryParser( "name", analyzer );
queryParser.setOperator( Operator.AND ); // Match *all* terms
Query luceneQuery = queryParser.parse( userInput );

...但这不会生成模糊查询。如果你想要模糊查询,你可以尝试重写 QueryParser 的自定义子类中的一些方法。我没有尝试过这个,但它可能有效:

public final class FuzzyQueryParser extends QueryParser {
private final int maxEditDistance;
private final int prefixLength;

public FuzzyQueryBuilder(String fieldName, Analyzer analyzer, int maxEditDistance, int prefixLength) {
super( fieldName, analyzer );
this.maxEditDistance = maxEditDistance;
this.prefixLength = prefixLength;
}

@Override
protected Query newTermQuery(Term term) {
return new FuzzyQuery( term, maxEditDistance, prefixLength );
}
}

编辑:当 minGramSize 为 1 时,您将获得大量非常频繁的术语:从单词开头提取的单个或两个字符的术语。它可能会导致许多不需要的匹配,这些匹配将获得高分(因为术语很频繁),并且可能会淹没精确匹配。

首先,您可以尝试将相似度(~评分公式)设置为org.apache.lucene.search.similarities.BM25Similarity,这样可以更好地忽略非常频繁的术语。请参阅here for the setting 。这应该会提高使用相同分析器的得分。

其次,您可以尝试设置两个字段而不是一个:一个字段用于模糊自动完成,另一个字段用于非模糊、完整匹配。这可能会提高精确匹配的分数,因为用于精确匹配的字段索引的无意义术语会减少。只需这样做:

@Field(name = "name", analyzer = @Analyzer(definition = "text")
@Field(name = "name_autocomplete", analyzer = @Analyzer(definition = "edgeNgram")
private String name;

分析器“text”只是 answer you linked 中的分析器“edgeNGram_query” ;只需重命名即可。

继续编写两个查询,而不是如上所述的一个,但请确保针对两个不同的字段:

  org.apache.lucene.search.Query exactSearchByName = qb.keyword().onField("name")
.matching(userInput).createQuery();
org.apache.lucene.search.Query fuzzySearchByName = qb.keyword().fuzzy()
.withEditDistanceUpTo(1).onField("name_autocomplete")
.matching(userInput).createQuery();
org.apache.lucene.search.Query searchByName = qb.boolean().should(exactSearchByName).should(fuzzySearchByName).createQuery();
booleanQuery.add(searchByName, BooleanClause.Occur.MUST);

当然,不要忘记在这些更改之后重新索引。

关于java - 具有自动完成和模糊功能的 Hibernate 搜索,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61251848/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com