【问题标题】:Lucene: Prefix token-wise match OR prefix of exact matchLucene:前缀令牌匹配或完全匹配的前缀
【发布时间】:2014-12-19 13:51:56
【问题描述】:

我有几千个字符串看起来像这样

  • Foo-Bar-Herp
  • Foo-Bar-Derp
  • Baz-Blurb 别的东西

我想提供一个有效的搜索,以便

  • “foo bar”(标记化前缀)
  • “foo herp”(跳过标记)
  • “foo-bar-”(确切前缀)
  • “Bar-Herp”(中间的确切字符串)
  • “foo ba”(一个完整的标记和另一个标记的前缀)

等等。 全部返回第一个字符串(可能还有其他字符串),但是

  • “herp foo”(顺序错误,不重要)
  • “foo blerp”(不是所有标记)
  • “murp herp”(并非所有标记)

不要。

即正确的前缀匹配和令牌(可能是前缀)匹配都应该匹配,与大小写无关,但查询中的所有令牌都必须在文档中。

我使用 StandardAnalyzer 和带有前缀查询的通用 QueryParser 设置了典型的 Lucene 示例。

我想我可能需要一个 BinaryQuery 来声明我需要查询中的所有标记都在文档中,但我不太清楚要获取标记来构建它(查询是用户提供的)。我也意识到使用 StringField 而不是 TextField 可以为我提供确切的字符串匹配,而不是令牌匹配,但我不确定这是否可以与上述内容结合使用?

我应该怎么做?我什至不必使用 Lucene 来完成它,但它看起来很合适。

【问题讨论】:

  • 你说“foo herp”应该返回结果,但“foo derp”不应该——前提是你有 Foo-Bar-Herp 和 Foo-Bar-Derp。你能详细说明一下吗?
  • 我只是说它不应该返回第一个结果。它应该返回第二个结果。更改示例。

标签: java lucene


【解决方案1】:

您的第一个(非关键)有点棘手,但要确保在所有结果中都能找到查询中的所有术语,您只需将所有查询术语设为必需。您可以使用添加的加号运算符来做到这一点:

  • +foo +bar
  • +foo +ba*(如果要处理前缀,则需要添加通配符来指定它,或者可能使用 ngram 标记器等)

或者,您可以将默认运算符设置为AND,使用StandardQueryParser.setDefaultOperator

queryParser.setDefaultOperator(StandardQueryConfigHandler.Operator.AND);

herp foofoo herp 的情况下,我认为,短语 slop 可能会将您带到您需要的地方。交换术语的顺序会增加两个距离,所以:

  • "foo herp"~2:匹配“Foo-Bar-Herp”
  • "herp foo"~2:没有

虽然短语查询不支持通配符,因此如果您需要将其与前缀术语结合使用,则会遇到问题。

如果您想在不更改顺序的情况下允许更多的slop,那么我相信您超出了QueryParser 表达您的查询的能力,并且需要转到SpanQuery API 来构造手动查询。

手动构建查询,您可以执行以下操作:

SpanQuery term1 = new SpanTermQuery(new Term("content", "foo"));
SpanQuery term2Prefix = new SpanMultiTermQueryWrapper(new PrefixQuery(new Term("content", "her")));
SpanQuery finalQuery = new SpanNearQuery(new SpanQuery[] {term1, term2Prefix}, 5, true);

按顺序查找第一个词条(完全匹配)和第二个词条的前缀,它们之间不超过五个词条。

【讨论】:

  • 这太好了,非常感谢。我不太关心订购的事情,但我确实关心“foo-bar-”(确切前缀)的工作,而它目前没有。即使使用相同的分析器,标记化在索引和搜索方面的工作方式是否不同?破折号是否被视为减号运算符?
猜你喜欢
  • 1970-01-01
  • 2022-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-09
  • 2020-05-19
  • 2019-01-11
  • 2013-06-03
相关资源
最近更新 更多