我将如何在 Postgres 表中的 varchar 列中查找包含相同 3 词短语的行?
其他问题中的大多数全文搜索建议都是将向量与特定查询进行比较,但我正在寻找的是包含任何 3 个词短语的行作为其他行。
例子:
SELECT *
FROM types t1
WHERE EXISTS (SELECT *
FROM types t2
WHERE t1.name phrase_matches t2.name
AND t1.id > t2.id)
在这里,phrase_matches
是一个组合操作,其中
'my foo bar baz' phrase_matches 'foo bar baz whatever'
返回 true
和
'my foo bar baz' phrase_matches 'foo baz whatever bar'
返回 false
编辑:来自 Google 的任何人的更新 - 没有临时表的解决方案,使用连接,在具有 18k 行的表上花费了一个多小时。临时表版本总共运行了几秒钟。
最佳答案
制作一个 trigrams-to-row-ids 表,然后在 trigram 列上自连接。浪费了很多空间,但这是最简单的方法。在 klin's answer to How to extract n-gram word sequences from text in Postgres 的帮助下:
-- your table
CREATE TABLE phrases (
id INT,
phrase TEXT
);
-- your data
INSERT INTO phrases (id, phrase) VALUES
(1, 'my foo bar baz'),
(2, 'foo bar baz whatever'),
(3, 'foo baz whatever bar');
-- function to extract word n-grams
-- from https://stackoverflow.com/a/51571001/240443
CREATE OR REPLACE FUNCTION word_ngrams(str TEXT, n INT)
RETURNS SETOF TEXT LANGUAGE plpgsql AS $$
DECLARE
i INT;
arr TEXT[];
BEGIN
str := regexp_replace(str, '[^[:alnum:]|\s]', '', 'g');
arr := string_to_array(str, ' ');
FOR i in 1 .. cardinality(arr) - n + 1 LOOP
RETURN NEXT array_to_string(arr[i : i+n-1], ' ');
END LOOP;
END $$;
-- table of all trigrams (my foo bar, foo bar baz, bar baz whatever...)
-- and rows they belong to
CREATE TEMPORARY TABLE trigrams (
id INT,
trigram TEXT
);
-- make sure JOIN doesn't take forever
CREATE INDEX ON trigrams (trigram, id);
-- extract the trigrams into their stylish new - yet temporary - home
INSERT INTO trigrams SELECT id, word_ngrams(phrase, 3) FROM phrases;
-- see which original rows have common trigrams
SELECT DISTINCT T1.id AS id1, T2.id AS id2
FROM trigrams T1 JOIN trigrams T2
ON T1.trigram = T2.trigram
AND T1 < T2;
-- | id1 | id2
---+-----+----
-- | 1 | 2
你也可以直接使用 word_ngrams
函数,不需要临时表,但是会慢很多。时间或空间,只选一个 :P 这将替换之前 CREATE TEMPORARY TABLE
代码片段中的所有内容(但仍然使用 klin 的精彩功能)。
SELECT DISTINCT T1.id AS id1, T2.id AS id2
FROM phrases T1 JOIN phrases T2
ON EXISTS (
SELECT word_ngrams(T1.phrase, 3)
INTERSECT
SELECT word_ngrams(T2.phrase, 3)
)
AND T1.id < T2.id;
-- | id1 | id2
---+-----+----
-- | 1 | 2
关于postgresql - PostgreSQL 中的短语比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53669690/