PgSQL · 特性介绍 · 全文搜索介绍

背景

在日常的数据处理中,我们经常会有这样的需求:从一个文本中寻找某个字符串(比如某个单词)。

对这个需求,我们可以用类似这样的SQL完成:SELECT * FROM tbl WHERE text LIKE ‘%rds PostgreSQL%’;(找到含有“rds PostgreSQL”的文本)。

现在我们考虑一些特殊的情形:

  1. 需要查找的文本特别多,特别大;
  2. 不做单纯的字符串匹配,而是考虑自然语言的一些特性,比如匹配某一类字符串(域名、人名)或者匹配单词的所有形式(不考虑它的词性及变化,比如have,has,had都匹配出来);
  3. 对中文自然语言特性的支持。

那么此时再用以上的 “SELECT … LIKE …” 就不明智了,因为对数据库来说,这样的SQL必然走的是全表扫描,那么当文本特别多、特别大的时候,查找效率就会很低。

另外,这样的SQL也不会智能到可以处理自然语言的特性。

怎么办呢?PostgreSQL(以下简称PG)提供了强大的全文搜索功能可以满足这样的需求。

对文本的预处理

全文搜索首先需要对文本预处理,包括3步:

  1. 将文本分解成一个个token,这些token可以是数字、单词、域名、人名、email的格式等等。在PG中可以定义一个parser来做这个工作。
  2. 将第一步分解成的token标准化,所谓的标准化就是利用一些规则将token分好类(比如人名是一类、域名是一类等等)。标准化后的token我们称之为lexeme。在PG中是通过定义一个词典来做这个工作。PG里最简单的词典simple的标准化过程就是将大写字母转成小写字母。
  3. 对文本打分,优化查找过程,比如对于待查找的词,文本1匹配的数量大于文本2匹配的数量,那么在这个查找过程,文本1的优先级大于文本2的优先级。

在PG中,以上对文本的预处理可以通过一个函数to_tsvector来完成,函数的返回值是tsvector这个数据类型。

另外,对于待查找的单词,我们也要用to_tsquery这个函数包装起来,函数的返回值是tsquery这个数据类型。

一个简单的例子见下面,to_tsquery里的参数可以使用运算符(&:与、|:或、!:非):

SELECT to_tsvector('fat cats ate fat rats') @@ to_tsquery('fat & rat');
 ?column?
----------
 t

Quick Start

在了解了这些概念之后,我们用实际的例子来玩一玩PG的全文搜索。

我们在client端输入以下命令,\dFp显示的是所有的parser,这里只有一个默认parser(default)。

\dFp+ default 显示默认parser(default)的详细信息:parse的过程(5个函数),parse的Token类型(asciihword, asciiword…)。

sbtest=# \dFp
        List of text search parsers
   Schema   |  Name   |     Description
------------+---------+---------------------
 pg_catalog | default | default word parser
(1 row)

sbtest=# \dFp+ default
    Text search parser "pg_catalog.default"
     Method      |    Function    | Description
-----------------+----------------+-------------
 Start parse     | prsd_start     | (internal)
 Get next token  | prsd_nexttoken | (internal)
 End parse       | prsd_end       | (internal)
 Get headline    | prsd_headline  | (internal)
 Get token types | prsd_lextype   | (internal)

        Token types for parser "pg_catalog.default"
   Token name    |               Description
-----------------+------------------------------------------
 asciihword      | Hyphenated word, all ASCII
 asciiword       | Word, all ASCII
 blank           | Space symbols
 email           | Email address
 entity          | XML entity
 file            | File or path name
 float           | Decimal notation
 host            | Host
 hword           | Hyphenated word, all letters
 hword_asciipart | Hyphenated word part, all ASCII
 hword_numpart   | Hyphenated word part, letters and digits
 hword_part      | Hyphenated word part, all letters
 int             | Signed integer
 numhword        | Hyphenated word, letters and digits
 numword         | Word, letters and digits
 protocol        | Protocol head
 sfloat          | Scientific notation
 tag             | XML tag
 uint            | Unsigned integer
 url             | URL
 url_path        | URL path
 version         | Version number
 word            | Word, all letters
(23 rows)

输入\dF+ english,给出标准化各类英语token时所用到的dictionary:

sbtest=# \dF+ english
Text search configuration "pg_catalog.english"
Parser: "pg_catalog.default"
      Token      | Dictionaries
-----------------+--------------
 asciihword      | english_stem
 asciiword       | english_stem
 email           | simple
 file            | simple
 float           | simple
 host            | simple
 hword           | english_stem
 hword_asciipart | english_stem
 hword_numpart   | simple
 hword_part      | english_stem
 int             | simple
 numhword        | simple
 numword         | simple
 sfloat          | simple
 uint            | simple
 url             | simple
 url_path        | simple
 version         | simple
 word            | english_stem

创建以default为parser的配置defcfg,并增加token映射,这里我们只关心email, url, host:

sbtest=# CREATE TEXT SEARCH CONFIGURATION defcfg (PARSER = default);
CREATE TEXT SEARCH CONFIGURATION
sbtest=# ALTER TEXT SEARCH CONFIGURATION defcfg ADD MAPPING FOR email,url,host WITH simple;
ALTER TEXT SEARCH CONFIGURATION

建好配置defcfg后,我们看看利用defcfg对文本进行处理的结果。这里使用to_tsvector函数,可以看到email,url,host都被识别出来了:

sbtest=# select to_tsvector('defcfg','xxx yyy xxx@taobao.com yyy@sina.com http://google.com/123 12345 ');
                              to_tsvector
-----------------------------------------------------------------------
 'google.com':4 'google.com/123':3 'xxx@taobao.com':1 'yyy@sina.com':2
(1 row)

在实际对表内的文本做全文搜索时,一般对目标列建立gin索引(也就是倒排索引,详情见官方文档),这样可以加快查询效率,具体操作如下:

sbtest=# CREATE TABLE t1(c1 text);
CREATE TABLE
sbtest=# CREATE INDEX c1_idx ON t1 USING gin(to_tsvector('defcfg', c1));
CREATE INDEX
sbtest=# \d t1
     Table "public.t1"
 Column | Type | Modifiers
--------+------+-----------
 c1     | text |
Indexes:
    "c1_idx" gin (to_tsvector('defcfg'::regconfig, c1))

这里我们插入2条文本,并做一些匹配:

sbtest=# INSERT INTO t1 VALUES('xxx yyy xxx@taobao.com yyy@sina.com http://google.com 12345');
INSERT 0 1
sbtest=# INSERT INTO t1 VALUES('xxx yyy xxx@gmail.com yyy@sina.com http://google.com 12345');
INSERT 0 1
sbtest=# select * from t1;
                             c1
-------------------------------------------------------------
 xxx yyy xxx@taobao.com yyy@sina.com http://google.com 12345
 xxx yyy xxx@gmail.com yyy@sina.com http://google.com 12345
(2 rows)

sbtest=# select * from t1 where to_tsvector('defcfg',c1) @@ 'google.com';
                             c1
-------------------------------------------------------------
 xxx yyy xxx@taobao.com yyy@sina.com http://google.com 12345
 xxx yyy xxx@gmail.com yyy@sina.com http://google.com 12345
(2 rows)

sbtest=# select * from t1 where to_tsvector('defcfg',c1) @@ to_tsquery('google.com & yyy@sina.com');
                             c1
-------------------------------------------------------------
 xxx yyy xxx@taobao.com yyy@sina.com http://google.com 12345
 xxx yyy xxx@gmail.com yyy@sina.com http://google.com 12345
(2 rows)

sbtest=# select * from t1 where to_tsvector('defcfg',c1) @@ to_tsquery('google.com & xxx@gmail.com');
                             c1
------------------------------------------------------------
 xxx yyy xxx@gmail.com yyy@sina.com http://google.com 12345
(1 row)

以上的操作都是针对英文,实际上对中文也是支持的,不过会稍微麻烦点,因为中文的token必须通过分词才能产生,所以需要先装分词的组件scws和zhparser,具体可以参考这篇博文

结语

本文对PG的全文搜索做了一个入门级的介绍,方便用户快速上手,如果需要对全文搜索作更深入的研究,建议阅读官方文档第12章

时间: 2024-10-30 18:14:30

PgSQL · 特性介绍 · 全文搜索介绍的相关文章

PostgreSQL SQL 语言:全文搜索

本文档为PostgreSQL 9.6.0文档,本转载已得到原译者彭煜玮授权.1. 介绍 全文搜索(或者文本搜索)提供了确定满足一个查询的自然语言文档的能力,并可以选择将它们按照与查询的相关度排序.最常用的搜索类型是找到所有包含给定查询词的文档并按照它们与查询的相似性顺序返回它们.查询和相似性的概念非常灵活并且依赖于特定的应用.最简单的搜索认为查询是一组词而相似性是查询词在文档中的频度. 文本搜索操作符已经在数据库中存在很多年了.PostgreSQL对文本数据类型提供了~.~*.LIKE和ILIK

MySQL中全文搜索详解介绍

二.语法       MATCH (col1,col2,...) AGAINST (expr [search_modifier])       search_modifier: { IN BOOLEAN MODE | WITH QUERY EXPANSION }       例如:SELECT * FROM tab_name WHERE MATCH (col1,col2) AGAINST (search_word);       这里的table需要是MyISAM类型的表,col1.col2需要

详细讲解PostgreSQL中的全文搜索的用法_数据库其它

开发Web应用时,你经常要加上搜索功能.甚至还不知能要搜什么,就在草图上画了一个放大镜. 搜索是项非常重要的功能,所以像elasticsearch和SOLR这样的基于lucene的工具变得很流行.它们都很棒.但使用这些大规模"杀伤性"的搜索武器前,你可能需要来点轻量级的,但又足够好的搜索工具. 所谓"足够好",我是指一个搜索引擎拥有下列的功能:     词根(Stemming)     排名/提升(Ranking / Boost)     支持多种语言     对拼

如何在Python的Flask框架中实现全文搜索?

  这篇文章主要介绍了在Python的Flask框架中实现全文搜索功能,这个基本的web功能实现起来非常简单,需要的朋友可以参考下 全文检索引擎入门 灰常不幸的是,关系型数据库对全文检索的支持没有被标准化.不同的数据库通过它们自己的方式来实现全文检索,而且SQLAlchemy在全文检索上也没有提供一个好的抽象. 我们现在使用SQLite作为我们的数据库,所以我们可以绕开SQLAlchemy而使用SQLite提供的工具来创建一个全文检索索引.但这么做不怎么好,因为如果有一天我们换用别的数据库,那么

使用 Microsoft SQL Server 2000 的全文搜索功能构建 Web 搜索应用程序

server|web|程序|全文搜索 使用 Microsoft SQL Server 2000 的全文搜索功能构建 Web 搜索应用程序 Andrew B. CenciniMicrosoft Corporation 2002年12月 适用于:    Microsoft SQL Server 2000摘要:学习如何充分利用 SQL Server 2000 的全文搜索功能.本文包含有关实现最大吞吐率和最佳性能的几点提示和技巧. 目录简介 全文搜索功能简介 配置全文搜索功能 全文查询 排位和优化 其他

Lucene.net 实现全文搜索

全文搜索 忙了几天终于实现一个简单的全文搜索在此回顾总结一下 本文介绍一下Lucene.Net 是什么?Lucene.Net 能作什么?以及怎么做的问题?最后给出 Lucene.Net 实现全文搜索的一个示例 1.Lucene.Net 是什么? Lucene.net 起初是一个开源项目然后转向商业化,也在Lucene.net 2.0已经发布,不过是要money D ,Lucene.net的命运有点类似于FreeTextBox ,它在 1.6.5 版本之后发布的 2.0 开始了商业路线,2.0 提

Sql Server全文搜索中文出错问题

本文介绍解决Sql Server全文搜索中文出错的问题,并提供实例下载参考. 解决中文字符出错问题: 方法一: 把文件复制到...\Microsoft sql server\MSSQL\FTDATA\SQLServer\Config\目录下(该路径为全文目录路径,可以全文目录属性中查看) 方法二: 编辑...\Microsoft SQL Server\MSSQL\FTDATA\SQLServer\Config\目录下的noise.chs文件,清空文档,输入'@'(其他的偏僻符号也可以) 最后,重

对JavaScript的全文搜索实现相关度评分的功能的方法

  这篇文章主要介绍了对JavaScript的全文搜索实现相关度评分的功能的方法,采用了一个名为Okapi BM25的算法,文中亦有介绍,需要的朋友可以参考下 全文搜索,与机器学习领域其他大多数问题不同,是一个 Web 程序员在日常工作中经常遇到的问题.客户可能要求你在某个地方提供一个搜索框,然后你会写一个类似 WHERE title LIKE %:query% 的 SQL 语句实现搜索功能.一开始,这是没问题,直到有一天,客户找到你跟你说,"搜索出错啦!" 当然,实际上搜索并没有&q

PgSQL · 特性分析 · checkpoint机制浅析

背景 上期月报PgSQL · 特性分析 · Write-Ahead Logging机制浅析中简单介绍了PostgreSQL中WAL机制,其中讲到如果是创建checkpoint会触发刷新xlog日志页到磁盘,本文主要分析下PostgreSQL中checkpoint机制. checkpoint又名检查点,一般checkpoint会将某个时间点之前的脏数据全部刷新到磁盘,以实现数据的一致性与完整性.目前各个流行的关系型数据库都具备checkpoint功能,其主要目的是为了缩短崩溃恢复时间,以Oracl