首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Hibernate搜索模糊超过2

Hibernate搜索模糊超过2
EN

Stack Overflow用户
提问于 2020-04-13 00:50:35
回答 2查看 543关注 0票数 0

我有一个带有hibernate、lucene和hibernate-search的Java后端。现在我想做一个模糊的查询,但是我不想让0、1或2在查询和预期的结果之间允许更多的“差异”(以补偿长单词中的拼写错误)。有办法做到这一点吗?允许的差异的最大值稍后将由查询的长度计算。

我想要这个,是一个自动完成搜索与纠正错误的字母。此自动完成只应搜索给定查询后面的缺失字符,而不应在其前面搜索。如果查询前面的字符与条目相比缺少,则应将它们计算为差异。

示例:本例中允许的最大不同字符为2。fooo应该匹配。

代码语言:javascript
复制
fooo       (no difference)
fooobar    (only characters added -> autocomplete)
fouubar    (characters added and misspelled -> autocomplete and spelling correction)

fooo不应该匹配

代码语言:javascript
复制
barfooo    (we only allow additional characters behind the query, but this example is less important)
fuuu       (more than 2 differences)

这是SQL查询的当前代码:

代码语言:javascript
复制
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周围的所有事情,而hibernate不每次都需要自定义代码。
  3. 这段代码已经起作用了,但只适用于withEditDistanceUpTo(2),这意味着QUERY_TO_MATCH与数据库或索引中匹配条目之间的最大“差异”。缺少的字符也算作差异。
  4. withEditDistanceUpTo(2)不接受大于2的值。

有人有什么办法来达到这个目的吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-05-03 15:54:39

好吧,我和我的朋友找到了解决办法。我们在lucene的changelog中找到了一个问题,它要求同样的特性,我们实现了一个解决方案:在lucene的沙箱版本中有一个SlowFuzzyQuery。它速度较慢(显然),但支持大于2的editDistance。

票数 0
EN

Stack Overflow用户

发布于 2020-04-14 11:21:32

我不知道有任何解决方案,您将指定允许更改的确切数量。

无论如何,这种方法有严重的缺点:将"foo“与最多3个更改相匹配意味着什么?有匹配的吗?正如您所看到的,使用不同期限的解决方案可能会更好。

一种解决办法是索引n克.我说的不是边-ngram,就像你已经做的那样,而是从整个术语中提取的实际ngram,而不仅仅是边缘。因此,当索引2克foooo时,您可以索引:

  • fo
  • oo (多次发生)

当查询时,术语fouuu将被转换为:

  • fo
  • ou
  • uu

..。而且它将匹配索引文档,因为它们至少有一个共同术语(fo)。

显然有一些缺点。对于2克,术语fuuuufoooo不匹配,而barfooo则与之匹配,因为它们有一个2克的共同点。这样你就会得到假阳性。克越长,你得到假阳性的可能性就越小,但你的搜索越模糊。

你可以依靠得分和按分数排列最好的比赛排在结果列表的第一位,从而使这些假阳性结果消失。例如,您可以配置ngram过滤器以保留原始术语,这样fooo将被转换为fooofooo,而不仅仅是fooo,因此,对包含fooo的文档进行精确搜索比对包含barfooo的文档(因为匹配更多)获得更好的分数。您还可以设置多个单独的字段:一个没有ngram,一个有3克,一个有2克,并构建一个布尔查询,每个字段都使用should子句:匹配的子句越多,得分就越高,在点击中找到的文档就越高。

另外,我认为fooo和类似的都是人为的例子,在真实的数据集中不太可能有这些术语;您应该尝试任何针对真实数据集的解决方案,看看它是否有效。如果你想要模糊搜索,你将不得不接受一些假阳性:问题不是它们是否存在,而是它们是否足够罕见,用户仍然可以很容易地找到他们正在寻找的东西。

为了使用ngram,请使用org.apache.lucene.analysis.ngram.NGramFilterFactory应用ngrams过滤器.无论是在索引时还是在查询时都应用它。使用参数minGramSize/maxGramSize配置ngram的大小,使用keepShortTerm (true/false)控制是否保留原始术语。

您可以保留边缘ngram过滤器或不;看看它是否提高了您的结果的相关性?我怀疑如果您使用keepShortTerm = true,它可能会稍微提高相关性。在任何情况下,确保在ngram过滤器之前应用边缘ngram过滤器.

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61180101

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档