第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

首頁(yè) 慕課教程 SQL 入門教程 SQL 入門教程 實(shí)戰(zhàn)6:PostgreSQL全文檢索功能實(shí)戰(zhàn)

實(shí)戰(zhàn)6:PostgreSQL 全文檢索功能實(shí)戰(zhàn)

1. 前言

本小節(jié),我們一起來(lái)學(xué)習(xí) PostgreSQL 中的一大殺器——FTS(Full Text Search,全文檢索)。

提到全文搜索,你是否立刻想到了大名鼎鼎的LuceneElasticsearch。Elasticsearch 基于 Lucene ,并為開(kāi)發(fā)者提供豐富的接口和工具,但是這也造成了它日益龐大。

使用它,你得備上一個(gè)大的服務(wù)器,一個(gè)優(yōu)秀的運(yùn)維團(tuán)隊(duì),還要承受數(shù)據(jù)同步的心智負(fù)擔(dān)。但你的需求其實(shí)很簡(jiǎn)單,只是一個(gè)小功能搜索,或者一個(gè)簡(jiǎn)單的全站搜索。如果在項(xiàng)目的初期,花費(fèi)如此大成本在搜索上有些得不償失。

如果數(shù)據(jù)庫(kù)本身就支持全文檢索,那該多好啊!沒(méi)錯(cuò),PostgreSQL 就支持全文搜索,而且很強(qiáng)大,還支持插件擴(kuò)展定制。

2. FTS配置庫(kù)

2.1 PostgreSQL 默認(rèn) FTS

PostgreSQL 全文搜索是通過(guò) FTS 配置庫(kù)來(lái)支持的,大多數(shù) PostgreSQL 發(fā)行版都自帶了 10 個(gè)以上的 FTS 配置庫(kù),我們可以通過(guò)psql\dF命令來(lái)查看已安裝的配置庫(kù):

                  List of text search configurations
   Schema   |    Name    |                Description
------------+------------+--------------------------------------------
 pg_catalog | arabic     | configuration for arabic language
 pg_catalog | danish     | configuration for danish language
 pg_catalog | dutch      | configuration for dutch language
 pg_catalog | english    | configuration for english language
 pg_catalog | finnish    | configuration for finnish language
 pg_catalog | french     | configuration for french language
 pg_catalog | german     | configuration for german language
 pg_catalog | hungarian  | configuration for hungarian language
.......

可以看到 PostgreSQL 默認(rèn)已經(jīng)安裝了大量的 FTS 搜索配置庫(kù),但是很不幸沒(méi)有中文配置庫(kù)。但好在,PostgreSQL 支持插件的形式來(lái)擴(kuò)展 FTS,所以我們可以使用成熟的擴(kuò)展庫(kù)。

2.2 pg_jiebe FTS

jieba是國(guó)內(nèi)一個(gè)頗為著名分詞庫(kù),如果你是 Python 開(kāi)發(fā)者,那么一定聽(tīng)過(guò)它的大名。有貢獻(xiàn)者為 PostgreSQL 提供了 jieba 分詞插件——pg_jieba,讓我們可以在 PostgreSQL 使用到中文全文檢索。

如果你想跟著我們一起,完成本節(jié)的實(shí)戰(zhàn)內(nèi)容,那么請(qǐng)先點(diǎn)開(kāi)此鏈接安裝 pg_jieba。

如果你安裝成功,那么可以通過(guò)\dF命令來(lái)找到jieba相關(guān)的分詞配置:

 public     | jiebacfg   | Mix segmentation configuration for jieba
 public     | jiebahmm   | Hmm segmentation configuration for jieba
 public     | jiebamp    | MP segmentation configuration for jieba
 public     | jiebaqry   | Query segmentation configuration for jieba

可以看到jieba提供了4種分類器,它們分別對(duì)應(yīng)了不同的分詞算法,如果你感興趣,可以查閱相關(guān)的資料,這里我們不做過(guò)多的介紹,默認(rèn)使用jiebacfg即可。

3. 基本使用

3.1 FTS 流程

全文搜索大致可分為兩部分:

  1. 構(gòu)建文本對(duì)應(yīng)的索引(倒排索引)
  2. 通過(guò)搜索索引來(lái)找到對(duì)應(yīng)的文本

3.2 文本向量化

在 FTS 中,原始文本在構(gòu)建索引之前需要被向量化。原始文本(如:字符串)必須先被向量化后才能通過(guò) FTS 對(duì)其檢索,向量化后的內(nèi)容需要存儲(chǔ)到一個(gè)單獨(dú)的向量字段中,該向量的數(shù)據(jù)類型是tsvector

PostgreSQL 提供了to_tsvector函數(shù)來(lái)將原始文本向量化,如下:

SELECT * FROM to_tsvector('jiebacfg','SQL,你敢吃我俺老孫一棒嗎?');
                to_tsvector
-------------------------------------------
 'sql':1 '一棒嗎':9 '吃':5 '敢':4 '老孫':8

tsvector是由(詞,序列)元組組成的列表,如sql是原始文本中的第一個(gè)詞,所以它的序列是1。

3.3 搜索關(guān)鍵字向量化

有了索引后,我們?nèi)绾蝸?lái)搜索索引了?

一般情況下,我們是通過(guò)關(guān)鍵詞來(lái)檢索的,那么如何來(lái)組織關(guān)鍵詞呢?

PostgreSQL 提供了to_tsquery函數(shù)來(lái)將詞組織成tsquery向量,然后通過(guò)向量去搜索。如下:

SELECT to_tsquery('sql & java');
   to_tsquery
----------------
 'sql' & 'java'

tsquery是一種特殊的數(shù)據(jù)類型,它會(huì)將關(guān)鍵詞拼接來(lái)表示搜索條件,如&表示搜索的內(nèi)容必須包含sql和java。舉個(gè)復(fù)雜的例子:

SELECT to_tsquery('sql & (java | python)');
          to_tsquery
-------------------------------
 'sql' & ( 'java' | 'python' )

這個(gè)例子表示,搜索的內(nèi)容必須包含sqljava與python中的一種。

3.4 搜索關(guān)鍵句向量化

當(dāng)然你也可以使用句子來(lái)搜索:

SELECT * FROM to_tsquery('jiebacfg','SQL難道不香嗎?');
        to_tsquery
---------------------------
 'sql' & '難道' & '不香嗎'

在輸入句子的情況下,to_tsquery會(huì)自動(dòng)將句子分詞,然后將其拼接為tsquery

3.5 FTS 總結(jié)

我們總結(jié)一下 FTS 的使用:

  1. 原始文本,即字符串不能被直接搜索,我們通過(guò) to_tsvector 函數(shù)將其向量化為詞組,并保存到某個(gè)字段中,該字段數(shù)據(jù)類型為 tsvector。
  2. tsvector 的字段存儲(chǔ)的是詞與詞序列的元組,需要新建 gin 索引才能使用搜索,下面會(huì)介紹。
  3. 搜索條件,狹義上可以理解成搜索關(guān)鍵字,也需要通過(guò) to_tsquery 來(lái)向量化,且類型為 tsquery。
  4. 使用 tsquery 去搜索 tsvector,在下面的部分會(huì)介紹到。

4. 實(shí)踐

接下來(lái),我們以實(shí)踐的角度來(lái)使用和學(xué)習(xí)一下 FTS。

4.1 文章搜索

假設(shè)某個(gè)應(yīng)用有一個(gè)文章搜索功能點(diǎn),我們將通過(guò) FTS 來(lái)實(shí)現(xiàn)它。

首先,我們新建文章數(shù)據(jù)表:

DROP TABLE IF EXISTS article;
CREATE TABLE article
(
  id      serial PRIMARY KEY,
  title   varchar(40),
  content text
);

id是每篇文章的唯一標(biāo)識(shí),title是標(biāo)題,content是文章內(nèi)容,我們省略了其它信息。然后我們插入幾條記錄:

INSERT INTO article(id, title, content)
VALUES (1, '科學(xué)和人文誰(shuí)更有意義', '科學(xué)和人文誰(shuí)更有意義,發(fā)生了會(huì)如何,不發(fā)生又會(huì)如何。 本人也是經(jīng)過(guò)了深思熟慮,在每個(gè)日日夜夜思考這個(gè)問(wèn)題。 一般來(lái)講,我們都必須務(wù)必慎重的考慮考慮。 本人也是經(jīng)過(guò)了深思熟慮,在每個(gè)日日夜夜思考這個(gè)問(wèn)題。 馬云曾經(jīng)提到過(guò),最大的挑戰(zhàn)和突破在于用人,而用人最大的突破在于信任人。我希望諸位也能好好地體會(huì)這句話。 既然如此, 科學(xué)和人文誰(shuí)更有意義,發(fā)生了會(huì)如何,不發(fā)生又會(huì)如何。 富勒在不經(jīng)意間這樣說(shuō)過(guò),苦難磨煉一些人,也毀滅另一些人。這啟發(fā)了我, 塞內(nèi)加曾經(jīng)提到過(guò),勇氣通往天堂,怯懦通往地獄。這不禁令我深思。 '),
(2, '編程的藝術(shù)','對(duì)我個(gè)人而言,編程的藝術(shù)不僅僅是一個(gè)重大的事件,還可能會(huì)改變我的人生。 編程的藝術(shù),到底應(yīng)該如何實(shí)現(xiàn)。 伏爾泰曾經(jīng)提到過(guò),堅(jiān)持意志偉大的事業(yè)需要始終不渝的精神。這似乎解答了我的疑惑。 既然如何, 生活中,若編程的藝術(shù)出現(xiàn)了,我們就不得不考慮它出現(xiàn)了的事實(shí)。 我們不得不面對(duì)一個(gè)非常尷尬的事實(shí),那就是, 莎士比亞曾經(jīng)說(shuō)過(guò),拋棄時(shí)間的人,時(shí)間也拋棄他。這啟發(fā)了我, 編程的藝術(shù)因何而發(fā)生? 要想清楚,編程的藝術(shù),到底是一種怎么樣的存在。 編程的藝術(shù)的發(fā)生,到底需要如何做到,不編程的藝術(shù)的發(fā)生,又會(huì)如何產(chǎn)生。 既然如此, 那么。'),
(3, '生命在于創(chuàng)造','在這種困難的抉擇下,本人思來(lái)想去,寢食難安。 帶著這些問(wèn)題,我們來(lái)審視一下生命在于創(chuàng)造。 我認(rèn)為, 一般來(lái)說(shuō), 生命在于創(chuàng)造因何而發(fā)生? 可是,即使是這樣,生命在于創(chuàng)造的出現(xiàn)仍然代表了一定的意義。 生命在于創(chuàng)造,到底應(yīng)該如何實(shí)現(xiàn)。 問(wèn)題的關(guān)鍵究竟為何? 生活中,若生命在于創(chuàng)造出現(xiàn)了,我們就不得不考慮它出現(xiàn)了的事實(shí)。 生命在于創(chuàng)造因何而發(fā)生? 莎士比亞曾經(jīng)提到過(guò),人的一生是短的,但如果卑劣地過(guò)這一生,就太長(zhǎng)了。我希望諸位也能好好地體會(huì)這句話。');

4.2 構(gòu)建文章索引

有了標(biāo)題和內(nèi)容后,我們需要為每篇文章單獨(dú)新建一個(gè)字段fts用來(lái)表示每篇文章的 tsvector 字段,并且給 fts 字段創(chuàng)建 gin 索引,這樣后面就可以通過(guò)該字段來(lái)搜索文章了。

ALTER TABLE article ADD COLUMN fts tsvector;
UPDATE article
SET fts = setweight(to_tsvector('jiebacfg', title), 'A') ||
          setweight(to_tsvector('jiebacfg', content), 'B');
CREATE INDEX article_fts_gin_index ON article USING gin (fts);

在 SQL 語(yǔ)句中,我們首先為article數(shù)據(jù)表新增了一個(gè)fts字段,字段類型為tsvector。有了該字段后,我們需要為該字段賦值,通過(guò)to_tsvector我們將每篇文章的titlecontent分別向量化。

由于titlecontent的重要性不一樣,文章的標(biāo)題明顯比內(nèi)容數(shù)據(jù)更加重要,因此setweight設(shè)置標(biāo)題的權(quán)重為A,而內(nèi)容的權(quán)重為B,A的重要性大于B。||操作符合并向量后將結(jié)果賦給fts。

到此,article 表中新增了一個(gè) fts 字段,字段中是標(biāo)題和內(nèi)容詞組的列表。最后為 fts 字段我們新建了索引 article_fts_gin_index 來(lái)加速我們的搜索效率。

提示: || 操作符是 PostgreSQL 的一個(gè)特點(diǎn),表示連接、合并。

4.3 使用 FTS

接下來(lái),我們便可以使用全文搜索了,搜索條件是文章需包含問(wèn)題關(guān)鍵字,如下:

SELECT title FROM article WHERE fts @@ to_tsquery('問(wèn)題');
        title
----------------------
 科學(xué)和人文誰(shuí)更有意義
 生命在于創(chuàng)造

PostgreSQL 提供@@操作符來(lái)搜索,上面語(yǔ)句將問(wèn)題通過(guò)to_tsquery轉(zhuǎn)化為向量后,使用@@來(lái)搜索。從結(jié)果中可以看出,與問(wèn)題相關(guān)的文章有兩篇。

注意: 在 article 表中,只有 fts 是 tsvector 字段,因此只有它能使用 @@ 操作符。

我們?cè)賴L試一下復(fù)雜的搜索,搜索條件是文章必須含有問(wèn)題生命兩個(gè)關(guān)鍵字:

SELECT title FROM article WHERE fts @@ to_tsquery('問(wèn)題 & 生命');
    title
--------------
 生命在于創(chuàng)造

4.4 完善文章搜索

從結(jié)果中可以看到,全文搜索已經(jīng)可以工作了,但它還不完備,如果更新或者添加文章,內(nèi)容發(fā)生了改變,那么索引也應(yīng)該隨之變化,我們可以使用觸發(fā)器來(lái)解決這個(gè)需求點(diǎn)。運(yùn)行如下 SQL:

DROP TRIGGER IF EXISTS trig_article_insert_update ON article;
CREATE TRIGGER trig_article_insert_update
  BEFORE INSERT OR UPDATE OF title,content
  ON article
  FOR EACH ROW
EXECUTE PROCEDURE tsvector_update_trigger(fts, 'public.jiebacfg', title, content);

有了 trig_article_insert_update 這個(gè)觸發(fā)器后,article 表中插入或 title,content 的更新都會(huì)引起 fts 向量的重建,由此一個(gè)比較完備的全文檢索功能點(diǎn)也就完成了。

我們的全文搜索實(shí)戰(zhàn)到此就結(jié)束了,你完全可以按照這種模式改編成你自己的應(yīng)用,讓它支持炫酷的全文搜索功能。

5. 小結(jié)

  • PostgreSQL的全文搜索的功能還是非常強(qiáng)大的,本節(jié)內(nèi)容僅僅只是一部分,你可以閱讀官方文檔獲取更多的信息。
  • 如果你需要強(qiáng)大的全文搜索功能以及數(shù)據(jù)分析能力,Elasticsearch或許更加適合你。