【问题标题】:Regex reverse search using Lucene使用 Lucene 的正则表达式反向搜索
【发布时间】:2021-06-22 13:25:47
【问题描述】:

假设我存储的 Lucene 文档有一个代表正则表达式的 regex 存储字段。

doc.add(new StringField("regex", "\d{3}[A-G]\d{2}[A-G]\d{2}", Store.YES));

我的搜索输入类似于123D56G89

有没有办法在我的 TermQuery 中进行反向匹配并获取与给定输入匹配的所有文档?

来自 RDBMS 背景,MariaDB 有REGEXP 功能。

【问题讨论】:

  • 你的意思是匹配除了与上述模式匹配的字符串之外的任何字符串?喜欢"^(?!\d{3}[A-G]\d{2}[A-G]\d{2}$).*"
  • 我的意思是:获取输入 123D56G89,使用其保存的正则表达式匹配该输入的所有文档对其进行评估并返回这些文档(如果有)。
  • 这是开箱即用的,还是我必须编写自己的自定义查询类?
  • 开箱即用的唯一查询类型 - RegexpQuery - 反过来工作:为查询提供一个正则表达式,用于测试索引数据中的纯字符串。此外,正则表达式的 Lucene 风格是 not full-featured
  • 是这样想的。实现我想要的东西可能有点矫枉过正:(

标签: java regex lucene


【解决方案1】:

如果您想利用搜索索引功能在亚线性时间内搜索许多文档,那么,根据您问题中给出的信息,没有办法。您必须检查索引中的每个文档并对每个文档的存储表达式进行操作。

正则表达式本质上是一种程序。 一般而言, 在无法推理表达式中编码的特定概念的情况下,评估它需要知道完整的表达式,并且引擎必须实际运行它。这意味着没有办法一般将字段汇总或分类到搜索索引中以加快查找速度。如果你想根据 N 个正则表达式检查一个字符串,你必须一个一个地检查这 N 个正则表达式并检查它们。那时,搜索索引并没有为存储、获取或管理它们提供任何好处。

如果您对“慢速”搜索完全没问题,并且不喜欢以这种方式存储任意表达式,那么从技术上讲是的,您可以实现一种新类型的查询来处理字段作为正则表达式并针对输入运行它。我不认为这是搜索索引的正常使用,但从技术上讲,这种逻辑与任何其他类型的评估一样。

但是,也许您正在尝试解决错误的问题。可能有更好的方法来表示您当前尝试存储为正则表达式的概念。如果您可以为匹配设计更具体的“语言”或结构,那么理论上,您可以创建一个分析器,将该数据转换为可索引和可​​优化的字段。

示例:也许您只是想使用正则表达式来匹配一些 ID 代码(如 1200ABC000121G021),基于数字的数量,然后是字母的数量,在其字首。在这种情况下,与其索引正则表达式,更好的办法是索引这两个数字:数字计数和前缀中的字母计数。因此,如果搜索字符串是DG56,我可能会搜索与numberPrefixWidth:0 letterPrefixWidth:2 之类的查询匹配的文档。或者对于搜索字符串789FGH4,我的查询将是numberPrefixWidth:3 letterPrefixWidth:3

因为我们已经简化了文档中实际表示的概念,所以无需查看每个文档(并且基本上运行一个存储的程序)来找到匹配的那个。我们可以使用 Lucene 进行快速搜索。

注意:此答案也适用于您的 RDBMS 示例。如果你想在 MariaDB 中做一些事情,比如WHERE someSearch REGEXP theRegexpColumn,引擎必须遍历每一行并评估它。在这样的设计中,没有任何基于索引的优化潜力。不同之处在于 Lucene 更具有特殊用途,并且没有 SQL 那样广泛的语言能够轻松运行这样的查询,而无需自己做一些工作。

【讨论】:

  • 首先感谢您的详尽解答! MariaDB 中的 REGEXP 运算符评估速度非常快,但仍不如 Lucene 快(没有 regex 位)。为了解决上述问题,我解决了它。我最终对所有其他搜索条件(但对于正则表达式字段)运行了一个 Lucene 查询,确保我最终得到一堆结果(
猜你喜欢
  • 2014-12-28
  • 2013-05-06
  • 2022-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-15
  • 1970-01-01
  • 2014-01-23
相关资源
最近更新 更多