如何以可索引的方式搜索字符串列的首字母缩略词

问题描述 投票:0回答:1

我正在开发一个express.js项目,使用Sequelize作为orm,使用postgres作为引擎。

我正在努力提高执行许多操作的慢速选择查询的性能,其中之一是将仓库名称的首字母缩略词与使用 ilike 的搜索词进行比较,因此如果搜索词是“STW”,名为“超级测试仓库”的仓库将匹配。查询如下所示:

SELECT field1, field2, ...
FROM package p
LEFT OUTER JOIN warehouse w ON p.warehouse_id = w.id
-- many other joins
WHERE
    regexp_replace(w.name, '([a-z ])+', '', 'g') ILIKE '%search term%'
    -- many other conditions

问题是,我正在做的主要改进是创建索引(gin 为所有所做的事情

ilike '%something%'
),并重构查询以便能够使用它们。但
regexp_replace()
函数不适用于索引。另一个需要注意的重要事项是,此解决方案仅在名称中的所有单词都正确大写的情况下才有效,这是我们大多数数据的情况,但不是全部,因此如果有一个名为“Super TEST Warehouse”的仓库,或“超级测试仓库”,将无法正常工作。

我想到的一个简单的解决方案就是这样做(假设搜索文本是“STW”):

w.name ILIKE 'S% T% W%' OR w.name ILIKE '% S% T% W%'

它适用于一般情况,并且使用我创建的杜松子酒索引。但问题是它允许中间有其他词。所以“STW”也会匹配“Super Fake Test Warehouse”。

是否有任何条件可以正确匹配首字母缩略词,并使用索引?

您是否建议为此使用生成的列(假设我改进现有的 regexp_replace,或使用其他东西)?这样做有什么缺点吗?理想情况下,我不想仅为此功能更改表,但如果我们无能为力,这可能是一个很好的解决方案。

还有其他解决办法吗?

sql postgresql indexing pattern-matching postgresql-performance
1个回答
0
投票

理想情况下,我不想仅为此功能更改表

因此创建一个表达式索引:

CREATE INDEX foo ON package (upper(regexp_replace(name, '\W*?\m(.).*?\M', '\1', 'g')));

该表达式可靠地提取大写首字母缩略词(字符串中尾随的非单词字符除外):

SELECT upper(regexp_replace('SUPER ware hOUse', '\W*?\m(.).*?\M', '\1', 'g'));  -- SWH

所涉及的函数是不可变的,因此适合表达式索引。

重复查询中的表达式以引入索引:

SELECT *
FROM   package p
WHERE  upper(regexp_replace(name, '\W*?\m(.).*?\M', '\1', 'g')) = 'SWH';

不过,我更愿意添加一个生成的列。查询更简单,速度更快,但每行仅添加很少的字节。参见:

© www.soinside.com 2019 - 2024. All rights reserved.