全文搜索是一种通过匹配查询中的单词或短语来搜索大量文档或数据的技术。它优于传统搜索,因为它可以按照与查询相似的顺序对搜索结果进行分类。传统搜索涉及与精确术语或短语匹配的简单查询。在这种情况下,使用了像LIKE
和ILIKE
这样的运营商。但是,全文搜索以此限制为基础,并允许在执行搜索之前对自然语言文档进行预处理。
如果您需要在包含文本数据的大文档上执行文本搜索,则全文搜索是必经之路。本文涵盖了基础知识,用例以及如何优化全文搜索。和我同行。
to_tsvector和to_tsvector在PostgreSQL中
在PostgreSQL中,全文搜索的两个常用功能是:
to_tsvector:
此函数用于将文档的文本转换为代币的向量(单词),每个令牌都与其归一化形式相关联。 to_tsvector
函数执行多个过程作为其标准化的一部分,例如;
- 令牌化:文本分为单个令牌或单词。文本是根据标点符号和空间分开的。
- 下刻:所有令牌均转换为小写。这确保了文本案例敏感性。
- stemming:所有令牌都被简化为其根部形式,称为“词汇”。后缀和结尾被删除。例如,“相信”,“信徒”和“相信”将被驱使“相信”。
- 停止词删除 - 停止单词是常用单词(例如“是”,“”,“和”),对文档的含义没有重大贡献。 该功能还将位置信息分配给每个令牌,指示其在原始文本中的位置。
归一化是全文索引和搜索的关键步骤。
例如;
-- Convert text to tsvector
SELECT to_tsvector('english', 'Innovative technologies are shaping the future');
此查询将生成像
的代币向量
'futur':6 'innov':1 'shape':4 'technolog':2
“英语”作为参数传递到to_tsvector函数中以指示文本搜索配置。
to_tsquery:
此功能用于将查询字符串转换为可用于全文搜索的查询表达式。它考虑到与to_tsvector
相同的语言配置。例如;
-- Convert text to tsquery
SELECT to_tsquery('english', 'cat & rat');
此查询将创建一个查询表达式,以查找包含“ CAT”和“ RAT”的文档。
全文搜索操作员
1.匹配操作员(“ @@”)
匹配运算符@@
用于测试TSVector是否匹配TSQUERY。如果文档包含查询指定的令牌和运算符,则返回true,否则为false。
例如,考虑一个名为books
的表格,带有名为title
的列,其中包含各种书的标题:
| ID | Title |
|----|--------------------------------------------|
| 1 | The Hitchhiker''s Guide to the Galaxy |
| 2 | One Hundred Years of Solitude |
| 3 | Pride and Prejudice and Zombies |
| 4 | The Girl with the Dragon Tattoo |
| 5 | To Kill a Mockingbird |
| 6 | The Perks of Being a Wallflower |
| 7 | The Curious Incident of the Dog in the Night-Time |
| 8 | The Fault in Our Stars |
| 9 | The Catcher in the Rye |
| 10 | The Lost Girl of Paris |
| 11 | Under the Stars'' Embrace |
可以在GitHub
上找到源代码,包括用于创建此表的查询
我们可以使用匹配操作员找到所有在标题中拥有“女孩”一词的书。这是实现这一目标的查询:
-- Select books where the title matches the tsquery 'Girl'
SELECT * FROM books
WHERE to_tsvector('english', title) @@ to_tsquery('english', 'Girl');
此查询返回以下输出:
| ID | Title |
|----|--------------------------------------------|
| 4 | The Girl with the Dragon Tattoo |
| 10 | The Lost Girl of Paris |
2.&(and)操作员
当搜索多个单词时,该操作员将在查询中使用。多个单词通常由“&”分开,查询仅返回所有单词都存在的文档
例如,
-- Select books where the title matches the tsquery 'girl' and 'dragon'
SELECT * FROM books
WHERE to_tsvector('english', title) @@ to_tsquery('english', 'girl & dragon');
在此查询中,&
符号代表AND
操作员。它将创建一个查询表达式以找到包含“女孩”和“龙”的文档,从books
表中与id“ 4”匹配。
| ID | Title |
|----|--------------------------------------------|
| 4 | The Girl with the Dragon Tattoo |
3. | (OR)操作员
该操作员在查询中使用以查找至少包含指定搜索词之一的文档。
假设我们想在“书籍”桌子的标题中找到具有“星系”或“星星”的书籍。我们可以使用或操作员来实现这一目标:
-- Select books where the title matches the tsquery 'Galaxy' or 'Stars'
SELECT * FROM books
WHERE to_tsvector('english', title) @@ to_tsquery('english', 'Galaxy | Stars');
|
符号代表OR
运算符。查询将匹配包含“ Galaxy”,“星星”或两者的文档。
上面的查询返回以下结果:
| ID | Title |
|----|--------------------------------------------|
| 1 | The Hitchhiker''s Guide to the Galaxy |
| 8 | The Fault in Our Stars |
| 11 | Under the Stars'' Embrace |
4.! (非)操作员
此操作员在查询中使用以排除包含操作员使用的单词的文档。
-- Select books where the title does not match 'Perks'
SELECT * FROM books
WHERE to_tsvector('english', title) @@ to_tsquery('english', '!Perks');
!
符号代表NOT
操作员。查询将仅匹配不包含“ perks”一词的文档。
5. <->(其次是)操作员
这与AND
运算符一样起作用,但是文档中写入单词的顺序很重要。这两个词需要彼此相邻,而两者之间没有任何其他单词。
在这种情况下,即使表中有一排带有“一百年孤独”的标题,寻找“孤独”,然后是“一百”,也不匹配任何文档,因为“一百”不在“之后”之后。孤独”。
-- Select books where the title matches 'Hundred' followed by 'Solitude'
SELECT * FROM books
WHERE to_tsvector('english', title) @@ to_tsquery('english', 'Hundred <-> Solitude');
接下来是操作员的扩展名,使我们可以指定两个单词之间的差距,允许在我们试图在文档中匹配的两个单词的位置之间指定的单词。这是<N>
操作员。 “ n”表示一个整数,表示两个单词的位置之间的最大间隙长度。
例如,我们想找到句子“一百”和“孤独”一词彼此之间出现在3个字的范围内。我们可以使用<3>操作员如下:
-- Select books where the title matches 'Hundred <3> Solitude'
SELECT * FROM books
WHERE to_tsvector('english', title) @@ to_tsquery('english', 'Hundred <3> Solitude');
在此查询中,<3>运算符指定标题列中的“一百”和“孤独”之间的3个单词。查询将返回此结果:
| ID | Title |
|----|--------------------------------------------|
| 2 | One Hundred Years of Solitude |
创建索引
索引可以在完成文本搜索之前在表上创建。这些索引可帮助我们的数据库迅速找到我们正在搜索的相关文档。
通过在执行文本搜索之前设置索引,我们为数据库提供了一个快捷方式,以查找所需的信息。数据库可以遵循这些索引直接达到我们要寻找的数据,而不是扫描表中的每个记录,而是使过程更加有效。
-- Create an index on the 'title' column
CREATE INDEX title_idx ON books(title);
全文搜索带有预先计算的向量
在这里,为文本搜索向量创建了一个新列,然后在该列上创建索引。该方法比仅在表上创建索引并在查询处理过程中对文档进行矢量化的速度要快。我们可以将新列添加到已经加载的表格中,然后更新表以包含每行的向量。
-- Alter the books table to add a new column for tsvector
ALTER TABLE books ADD COLUMN title_tsvector tsvector;
-- Update the title_tsvector column for all rows
UPDATE books SET title_tsvector=to_tsvector('english',title);
-- Create an index on the 'title_tsvector' column using GIN
CREATE INDEX title_tsvector_idx ON books USING GIN(title_tsvector);
另外,我们可以在制作表格并利用“存储过程”时创建列来更新列,每当将新行添加到表中。
-- Create the books table with id, title, and title_tsvector columns
CREATE TABLE books (
id serial PRIMARY KEY,
title text,
title_tsvector tsvector
);
-- Create a stored procedure to update title_tsvector
CREATE OR REPLACE FUNCTION update_title_tsvector()
RETURNS TRIGGER AS $$
BEGIN
NEW.title_tsvector := to_tsvector('english', NEW.title);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Create a trigger to automatically update title_tsvector
CREATE TRIGGER update_title_tsvector_trigger
BEFORE INSERT ON books
FOR EACH ROW
EXECUTE FUNCTION update_title_tsvector();
排名搜索结果
全文搜索具有与查询相关的顺序排序结果的能力。它分配了一个分数,以指示每个匹配和查询之间的相似性水平。此功能使网络搜索引擎中的全文搜索合并到了,从而为用户提供了来自Internet上大量信息的相关搜索结果。它还使求职者能够根据关键字和标准搜索职位发布。
-- Selecting book ID, title, and calculated rank, and ordering the results by rank in descending order for relevance
SELECT id, title, ts_rank(to_tsvector('english', title), to_tsquery('english', 'stars')) AS rank
FROM books
WHERE title_tsvector @@ to_tsquery('english', 'stars')
ORDER BY rank DESC;
此查询检索书籍记录,标题中存在“星星”一词。然后根据其与搜索查询的相关性订购结果。由于查询在小表中搜索一个单词,因此两本书最终都可能具有相似的等级。
结论
全文搜索增强了大量文档或数据集合中的搜索功能。前面没有提到的全文搜索的另一个值得注意的功能是它可以分配权重,使我们在执行搜索时可以优先考虑某些单词。通过了解其功能和运营商,我们可以优化搜索并有效检索相关信息。