在数据库中搜索(相似)字符串的可扩展方式
Scalable way to search for (similar) strings in a database
让我描述一下我的问题。有一个输入字符串和一个包含数千个字符串的 table 。我正在寻找搜索与输入字符串最相似* 字符串的最佳方法。搜索应该 return 约 10 个建议字符串的列表,按相似度排序。字符串在数据库中的另一列中也有与之关联的数值权重(流行度),因此如果可能的话,权重较高的字符串出现在结果中的机会应该更大。
实现此目标的最佳库是什么?我想我正在寻找类似于 Elasticsearch 的东西。我对这些类型的库没有太多经验,所以我需要一些容易包含在我的项目中的东西,最好是开源的。我正在使用 Python(Flask 和 SQLAlchemy)和 Postgresql,但也可以使用例如Node.js,如果需要的话。
*我还想澄清一下我在寻找什么样的相似性。理想情况下,这将是语义相似性,但词汇相似性也很好。我会对任何工作正常、易于实施并且尽可能具有可扩展性和高性能的东西感到满意。
示例输入句子:
- 我不喜欢袋鼠。
来自数据库的示例建议:
- 袋鼠不是我的最爱。
- 袋鼠是邪恶的。
- 我曾经养过一只袋鼠。再也不会了。
这些建议应该首先出现,因为 'cangaroo' 在我的数据库中不是一个常用词,所以任何包含 'cangaroo' 的字符串应该很有可能出现在结果中。检测“不喜欢”可能更难,所以这部分对我来说完全是可选的。
P.s。 PostgreSQL 的全文搜索可以做这样的事情吗?
谢谢。
PostgreSQL 全文搜索无法满足您的要求。但是,PostgreSQL trigram similarity可以做到。
您首先需要安装 'trigram similarity' 和 'btree_gist' 的软件包,方法是在您的数据库中执行(一次):
CREATE EXTENSION pg_trgm;
CREATE EXTENSION btree_gist;
我假设你有一个 table 看起来像这个:
CREATE TABLE sentences
(
sentence_id integer PRIMARY KEY,
sentence text
) ;
INSERT INTO sentences (sentence_id, sentence)
VALUES
(1, 'Cangaroos are not my favorite.'),
(2, 'A vegetable sentence.'),
(3, 'Cangaroos are evil.'),
(4, 'Again, some plants in my garden.'),
(5, 'I once had a cangaroo. Never again.') ;
此 table 需要一个 'trigram index',以允许 PostgreSQL 数据库 'index by similarity'。这是通过执行:
CREATE INDEX ON sentences USING GIST (sentence gist_trgm_ops, sentence_id) ;
要找到您正在寻找的答案,请执行:
-- Set the minimum similarity you want to be able to search
SELECT set_limit(0.2) ;
-- And now, select the sentences 'similar' to the input one
SELECT
similarity(sentence, 'I don''t like cangaroos') AS similarity,
sentence_id,
sentence
FROM
sentences
WHERE
/* That's how you choose your sentences:
% means 'similar to', in the trigram sense */
sentence % 'I don''t like cangaroos'
ORDER BY
similarity DESC ;
您得到的结果是:
similarity | sentence_id | sentence
-----------+-------------+-------------------------------------
0.3125 | 3 | Cangaroos are evil.
0.2325 | 1 | Cangaroos are not my favorite.
0.2173 | 5 | I once had a cangaroo. Never again.
希望这能满足您的需求...
让我描述一下我的问题。有一个输入字符串和一个包含数千个字符串的 table 。我正在寻找搜索与输入字符串最相似* 字符串的最佳方法。搜索应该 return 约 10 个建议字符串的列表,按相似度排序。字符串在数据库中的另一列中也有与之关联的数值权重(流行度),因此如果可能的话,权重较高的字符串出现在结果中的机会应该更大。
实现此目标的最佳库是什么?我想我正在寻找类似于 Elasticsearch 的东西。我对这些类型的库没有太多经验,所以我需要一些容易包含在我的项目中的东西,最好是开源的。我正在使用 Python(Flask 和 SQLAlchemy)和 Postgresql,但也可以使用例如Node.js,如果需要的话。
*我还想澄清一下我在寻找什么样的相似性。理想情况下,这将是语义相似性,但词汇相似性也很好。我会对任何工作正常、易于实施并且尽可能具有可扩展性和高性能的东西感到满意。
示例输入句子:
- 我不喜欢袋鼠。
来自数据库的示例建议:
- 袋鼠不是我的最爱。
- 袋鼠是邪恶的。
- 我曾经养过一只袋鼠。再也不会了。
这些建议应该首先出现,因为 'cangaroo' 在我的数据库中不是一个常用词,所以任何包含 'cangaroo' 的字符串应该很有可能出现在结果中。检测“不喜欢”可能更难,所以这部分对我来说完全是可选的。
P.s。 PostgreSQL 的全文搜索可以做这样的事情吗?
谢谢。
PostgreSQL 全文搜索无法满足您的要求。但是,PostgreSQL trigram similarity可以做到。
您首先需要安装 'trigram similarity' 和 'btree_gist' 的软件包,方法是在您的数据库中执行(一次):
CREATE EXTENSION pg_trgm;
CREATE EXTENSION btree_gist;
我假设你有一个 table 看起来像这个:
CREATE TABLE sentences
(
sentence_id integer PRIMARY KEY,
sentence text
) ;
INSERT INTO sentences (sentence_id, sentence)
VALUES
(1, 'Cangaroos are not my favorite.'),
(2, 'A vegetable sentence.'),
(3, 'Cangaroos are evil.'),
(4, 'Again, some plants in my garden.'),
(5, 'I once had a cangaroo. Never again.') ;
此 table 需要一个 'trigram index',以允许 PostgreSQL 数据库 'index by similarity'。这是通过执行:
CREATE INDEX ON sentences USING GIST (sentence gist_trgm_ops, sentence_id) ;
要找到您正在寻找的答案,请执行:
-- Set the minimum similarity you want to be able to search
SELECT set_limit(0.2) ;
-- And now, select the sentences 'similar' to the input one
SELECT
similarity(sentence, 'I don''t like cangaroos') AS similarity,
sentence_id,
sentence
FROM
sentences
WHERE
/* That's how you choose your sentences:
% means 'similar to', in the trigram sense */
sentence % 'I don''t like cangaroos'
ORDER BY
similarity DESC ;
您得到的结果是:
similarity | sentence_id | sentence
-----------+-------------+-------------------------------------
0.3125 | 3 | Cangaroos are evil.
0.2325 | 1 | Cangaroos are not my favorite.
0.2173 | 5 | I once had a cangaroo. Never again.
希望这能满足您的需求...