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

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 背景 在日常的数据处理中,我们经常会有这样的需求:从一个文本中寻找某个字符串(比如某个单词)。 对这个需求,我们可以用类似这样的SQL完成:SELECT * FROM tbl WHERE text LIKE ‘%rds PostgreSQL%’;(找到含有“rds PostgreSQL”的文本)

背景

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

对这个需求,我们可以用类似这样的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章

目录
相关文章
|
存储 SQL 安全
MySQL · 引擎特性 · 安全及权限改进相关
MySQL8.0里引入了不少关于权限的改动,从这些改动可以看出来,权限管理更加的规范和遍历了,这和我们之前为rds mysql增加了大量权限管理很类似,想来Oracle也是通过这些改动为其云业务服务的吧。 本文主要简述下部分相关的权限改动,不会涉及代码实现部分。
189 0
|
关系型数据库 数据库 PostgreSQL
PgSQL · 特性分析 · 浅析PostgreSQL 中的JIT
--- title: PgSQL · 特性分析 · 浅析PostgreSQL 中的JIT author: 卓刀 --- ## 背景 估计很多同学看过之前的月报[PgSQL · 特性分析· JIT 在数据仓库中的应用价值](http://mysql.taobao.org/monthly/2016/11/10/),对JIT(just in time)和LLVM(Low Level Vir
2655 0
|
缓存 关系型数据库 数据库
MySQL · 引擎特性 · B+树并发控制机制的前世今生
前言 B+树是1970年Rudolf Bayer教授在《Organization and Maintenance of Large Ordered Indices》一文中提出的[1]。它采用多叉树结构,降低了索引结构的深度,避免传统二叉树结构中绝大部分的随机访问操作,从而有效减少了磁盘磁头的寻道次数,降低了外存访问延迟对性能的影响。
1395 0
|
缓存 监控 关系型数据库
MySQL · 引擎特性 · WAL那些事儿
前言 日志先行的技术广泛应用于现代数据库中,其保证了数据库在数据不丢的情况下,进一步提高了数据库的性能。本文主要分析了WAL模块在MySQL各个版本中的演进以及在阿里云新一代数据库POLARDB中的改进。
2276 0
|
自然语言处理 关系型数据库 MySQL
|
关系型数据库 MySQL 索引
MySQL · 引擎介绍 · Sphinx源码剖析(二)
在本节中,我将会介绍索引文件sph的生成,从上一节我们得知sph文件保存了Sphinx的索引元信息以及一些索引相关的配置信息 SPH文件生成 先来看代码,其中sph文件的生成是在CSphIndex_VLN::WriteHeader这个函数中: bool CSphIndex_VLN::WriteHeader ( const BuildHeader_t & tBuildHeader,
1828 0
|
存储 缓存 关系型数据库
PgSQL · 代码浅析 · PostgreSQL 可靠性分析
背景 PostgreSQL 可靠性与大多数关系数据库一样,都是通过REDO来保障的。 群里有位童鞋问了一个问题,为什么PostgreSQL的REDO块大小默认是8K的,不是512字节。 这位童鞋提问的理由是,大多数的块设备扇区大小是512字节的,512字节可以保证原子写,而如果REDO的块大于512字节,可能会出现partial write。 那么PostgreSQL的redo(wal) 块
2330 0
|
存储 关系型数据库 MySQL
MySQL · 特性分析 · MyRocks简介
RocksDB是facebook基于LevelDB实现的,目前为facebook内部大量业务提供服务。经过facebook大量工作,将RocksDB作为MySQL的一个存储引擎移植到MySQL,称之为MyRocks。 经过两年的发展,MyRocks已经比较成熟(RC阶段),现已进入了facebook MySQL的主分支了。MyRocks是开源的,参见git 。 下面对MyRocks做一个简单介绍,
2689 0
|
SQL 关系型数据库 测试技术
PgSQL · 特性分析 · PostgreSQL 9.6 如何把你的机器掏空
背景 PostgreSQL 在向和纵向的扩展能力在开源数据库中一直处于非常领先的地位,例如今年推出的9.6,内置了sharding的功能,同时在scale-up的能力也有非常明显的提升,特别是在多核与高并发处理这块。 社区有同学在128核的机器上测试tpc-b的select only模式可以达到几百万的qps,机器的CPU资源被吃光光。 天下大势,分久必合,合久必分。谈了这么多年的shardi
6058 0