利用Lucene进行正则表达式反向搜索

5
假设我的存储在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}$).*" - Wiktor Stribiżew
我的意思是:获取输入123D56G89,将其与所有保存的正则表达式匹配的文档进行评估,并返回这些文档(如果有)。 - theo
这是否可以直接实现,还是我需要编写自己的自定义查询类? - theo
1
唯一的开箱即用查询类型 - RegexpQuery - 的工作方式与众不同:查询会给出一个正则表达式,该表达式用于测试索引数据中的普通字符串。此外,Lucene 正则表达式的特性不是完整的 - andrewJames
可能是我想要实现的有点过头了 :( - theo
Lucene正则表达式支持匹配除特定字符串外的任何字符串,@&~([0-9]{3}[A-G][0-9]{2}[A-G][0-9]{2}) - Wiktor Stribiżew
1个回答

2
如果您想利用搜索索引功能在次线性时间内搜索多个文档,那么根据您提供的信息,没有方法。您必须检查索引中的每个文档并对每个文档的存储表达式进行操作。
正则表达式本质上是一种类型的程序。 通常情况下,为了评估它而不需要理解表达式中编码的特定概念,需要知道完整的表达式,并且引擎必须实际运行它。这意味着没有办法通常地将该领域总结或分类为搜索索引以加速查找。如果您希望检查字符串与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(不带正则表达式部分)快。为了解决这个问题,我绕了一个弯路。我最终运行了一个Lucene查询来处理所有其他搜索条件(但不包括正则表达式字段),确保我最终获得一堆结果(<10),然后逐个在内存中评估正则表达式(Java)。当然,这样做会有一些小惩罚,但暂时看起来结果还不错。 - theo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接