检查一个句子是否在pl / pgsql中的字符串中

时间:2012-11-05 13:56:58

标签: string postgresql plpgsql

我有一个pl / pgsql脚本需要检查一个单词/句子是否在一个字符串中,它必须处理单词边界,并且不区分大小写。

示例:

  • 字符串:“我的标签xx zz yy”,模式:“我的标签”,MATCH
  • 字符串:“xx my label zz”,Pattern:“my label”,MATCH
  • 字符串:“my labelxx zz”,Pattern:“my label”,NO MATCH

所以显而易见的解决方案是使用正则表达式,如下所示:

select _label ~* (E'\\y' || _pattern || E'\\y') into _match;

与简单的

相比,它有效,但速度很慢
select _label ilike '%' || _pattern || '%' into _match;

这包含在我的脚本调用A LOT的函数中(数以千万计,我做了大量的递归),并且根据这个要求,整个运行时间翻了一倍。

现在我的问题是,有更快的方法来实现这个吗?

感谢。

编辑:最终使用了这个:

if _label ilike '%' || _pattern || '%' then
    select _label ~* (E'\\m' || _pattern || E'\\M') into _match;
end if;

它明显更快。

1 个答案:

答案 0 :(得分:2)

我会考虑full text search功能,但根据您的描述,我可能会使用PostgreSQL arrays实现此功能。

首先:定义一个带标签的函数,将它缩小(或者如果你愿意的话大写),在字边界上拆分它,然后返回一个数组。说:

CREATE OR REPLACE FUNCTION label_to_array(text) RETURNS text[] AS $$
SELECT regexp_split_to_array(lower($1), E'\\W');
$$ LANGUAGE sql IMMUTABLE;

$ select label_to_array('my label xx zz yy');
   label_to_array    
---------------------
 {my,label,xx,zz,yy}

现在,在此功能上创建GIN index

CREATE INDEX sometable_label_array_key ON sometable
 USING GIN((label_to_array(label));

从这里开始,PostgreSQL可以将此索引用于涉及array operators的许多查询,例如“contains”:

SELECT *
FROM sometable
WHERE label_to_array(label) @> label_to_array('my label');

此查询会将'my label'拆分为{my,label},然后使用索引查找包含my的行列表,并将其与包含label的行列表相交},然后返回结果。这并不完全等同于您的原始查询(因为它不检查它们的顺序),但由于它使用索引来消除表中的大多数行,因此在末尾添加原始检查可以正常工作:< / p>

SELECT *
FROM sometable
WHERE label_to_array(label) <@ label_to_array('my label')
AND label ~* (E'\\y' || 'my label' || E'\\y');