[英]Hibernate search fuzzy more than 2
我有一个 Java 后端,带有 hibernate、lucene 和休眠搜索。 现在我想做一个模糊查询,但不是 0、1 或 2,我想允许查询和预期结果之间有更多的“差异”(以补偿例如长词中的拼写错误)。 有什么办法可以做到这一点? 稍后将根据查询的长度计算允许的最大差异。
我想要的是自动完成搜索并纠正错误的字母。 此自动完成应该只搜索给定查询后面的缺失字符,而不是前面的。 如果查询前面的字符与条目相比缺失,则应计为差异。
示例:此示例中允许的最大不同字符数为 2。 fooo
应匹配
fooo (no difference)
fooobar (only characters added -> autocomplete)
fouubar (characters added and misspelled -> autocomplete and spelling correction)
fooo
不应该匹配
barfooo (we only allow additional characters behind the query, but this example is less important)
fuuu (more than 2 differences)
这是我当前的 SQL 查询代码:
FullTextEntityManager fullTextEntityManager = this.sqlService.getFullTextEntityManager();
QueryBuilder queryBuilder = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(MY_CLASS.class).overridesForField("name", "foo").get();
Query query = queryBuilder.keyword().fuzzy().withEditDistanceUpTo(2).onField("name").matching("QUERY_TO_MATCH").createQuery();
FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(query, MY_CLASS.class);
List<MY_CLASS> results = fullTextQuery.getResultList();
笔记:
1. 我使用org.apache.lucene.analysis.ngram.EdgeNGramFilterFactory
进行索引,但这不应该做任何改变。
2.这是使用自定义框架,不是开源的。 您可以忽略sqlService
,它只提供FullTextEntityManager
并处理 hibernate 周围的所有事情,每次都不需要自定义代码。
3. 这段代码已经可以工作了,但只适用于withEditDistanceUpTo(2)
,这意味着QUERY_TO_MATCH
和数据库或索引中的匹配条目之间最多有 2 个“差异”。 缺少的字符也算作差异。
4. withEditDistanceUpTo(2)
不接受大于 2 的值。
有没有人有任何想法来实现这一目标?
我不知道有任何解决方案可以指定允许的确切更改数量。
无论如何,这种方法有严重的缺点:将“foo”与最多 3 个更改匹配意味着什么? 随便什么都配? 如您所见,适用于不同期限长度的解决方案可能会更好。
一种解决方案是索引 n-gram。 我不是在谈论边缘 ngram,就像你已经做过的那样,而是从整个术语中提取的实际 ngram,而不仅仅是边缘。 因此,当索引 2 克foooo
时,您将索引:
fo
oo
(出现多次) 在查询时,术语fouuu
将转换为:
fo
ou
uu
...并且它将匹配索引文档,因为它们至少有一个共同的术语( fo
)。
显然有一些缺点。 对于 2-gram,术语fuuuu
不会匹配foooo
,但术语barfooo
会匹配,因为它们有一个 2-gram 的共同点。 所以你会得到误报。 克数越长,您获得误报的可能性就越小,但您的搜索就越模糊。
您可以依靠得分和按得分排序将最佳匹配项放在结果列表中的首位,从而使这些误报 go 消失。 例如,您可以配置 ngram 过滤器以保留原始术语,这样fooo
将被转换为 [ fooo
, fo
, oo
] 而不仅仅是 [ fo
, oo
],因此精确搜索fooo
会有更好的分数对于包含fooo
barfooo
文档(因为匹配项更多)。 您还可以设置多个单独的字段:一个不带 ngram,一个带 3-gram,一个带 2-gram,并构建一个 boolean 查询,每个字段都带有 on should
子句:匹配的子句越多,得分越高,并且您会在点击中找到更高的文档。
另外,我认为fooo
和类似的东西确实是人为的例子,你不太可能在现实世界的数据集中拥有这些术语; 您应该尝试针对真实数据集提出的任何解决方案,看看它是否足够好。 如果你想要模糊搜索,你将不得不接受一些误报:问题不在于它们是否存在,而在于它们是否足够稀有以至于用户仍然可以轻松找到他们正在寻找的东西。
为了使用 ngram,请使用org.apache.lucene.analysis.ngram.NGramFilterFactory
应用 n-gram 过滤器。 在索引和查询时都应用它。 使用参数minGramSize
/ maxGramSize
配置 ngram 的大小,并keepShortTerm
( true
/ false
) 控制是否保留原始术语。
您可以保留或不保留 edge-ngram 过滤器; 看看它是否提高了结果的相关性? 我怀疑如果您使用keepShortTerm = true
可能会稍微提高相关性。 在任何情况下,请确保在 ngram 过滤器之前应用 edge-ngram 过滤器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.