1. 程式人生 > >分析型資料庫(AnalyticDB)-V2.7版本正式支援全文索引

分析型資料庫(AnalyticDB)-V2.7版本正式支援全文索引

AnalyticDB 全文索引介紹

背景

大資料處理技術經過若干年的發展,結構化資料檢索已經逐漸有了多元化的、豐富的解決方案。但是與此同時,比如文字、圖片、視訊等非結構化資料的產生速度越來越快,資料量急劇增長,亟需簡單易用的處理方法。

為了賦能使用者、降低使用者處理非結構化資料的難度,AnalyticDB在既有結構化資料極速分析能力的基礎上,進一步研發了非結構化文字資料的檢索功能,提供了結構化資料、非結構化資料融合檢索(也即多模分析)的能力。

功能特色

業界已有解決方案比如ElasticSearch、Apache Solr等雖然提供了一定的文字檢索能力,但是仍舊存在一些問題。與他們相比,AnalyticDB的功能特色是:

1)AnalyticDB通過SQL語言提供全文檢索功能。
目前ElasticSearch、Solr仍舊以RESTful/HTTP介面為主,缺乏完善的SQL支援。這不僅導致編碼複雜,而且語義表達也不夠簡潔明瞭。而AnalyticDB提供了完整的SQL92支援,且相容Mysql協議,不僅容易上手,極大的降低了使用者的學習成本;而且將常用的結構化資料分析操作,與靈活的非結構化資料分析操作統一,使用同一套SQL語言操作多種型別資料,大幅降低了開發成本。

2)AnalyticDB提供結構化資料、非結構化資料的融合檢索、多模分析能力。
大部分已有業界解決方案側重於在文字資料上構建全文索引,提供非結構化資料的分析能力,對於結構化資料的檢索能力支援不足。AnalyticDB在提供全文檢索功能的同時,還提供了傳統資料庫中多種經典索引結構,如B+Tree index, Bitmap index, Inverted index等,而且支援在同一張表中混用多種不同的索引以滿足多變的檢索需求。

3)AnalyticDB提供了完善的分散式計算能力。
當下ElasticSearch、Solr等缺乏完善的分散式Join解決方法。而基於成熟的MPP+DAG架構,AnalyticDB提供了完善的分散式Join、GroupBy、Aggregation能力,比如count(distinct)等,而且支援基於分割槽鍵與非分割槽鍵計算。

4)AnalyticDB內建了來自淘寶、天貓搜尋的智慧分片語件,分詞效果更好,速度更快。

使用者場景

建表

在AnalyticDB中結構化資料列是指型別為bool、int、float、varchar等可以進行等值查詢、範圍查詢的資料列;
而非結構化資料列是指型別為varchar、clob等需要進行全文檢索的資料列。

AnalyticDB支援將結構化資料列、非結構化資料列在一個表中同時定義,且支援進行結構化條件、非結構化條件聯合檢索。

其中結構化資料列預設會建立倒排索引,而非結構化資料列如果需要進行全文檢索,則需要在建表語句中顯式指定為該列建立fulltext index。

注意:建立了fulltext index的非結構化資料列,只支援全文檢索,不再支援等值查詢、範圍查詢、like查詢等。

需要建立全文索引的列,型別需要設定為varchar或clob; 一般建議為varchar

在建表語句中,通過語法

FULLTEXT INDEX <idx_name> (<col_name>)

指定為col_name這一列建立索引名字為idx_name的全文索引。

示例

-- 假設需要對articles_test表中型別為varchar的三列author, title, boby分別建立全文索引

create tablegroup test_group;

CREATE TABLE articles_test (
  id bigint COMMENT '',
  author varchar COMMENT '',
  title varchar COMMENT '',
  body varchar COMMENT '',
  comment varchar COMMENT '',
  create_time timestamp COMMENT '',
  FULLTEXT INDEX author_fulltext (author),
  FULLTEXT INDEX body_fulltext (body),
  FULLTEXT INDEX title_fulltext (title),
  PRIMARY KEY (id)
)
PARTITION BY HASH KEY(id)
PARTITION NUM 8
CLUSTERED BY (id)
TABLEGROUP test_group
OPTIONS (UPDATETYPE='realtime')
COMMENT '';

資料寫入

支援通過標準的SQL語法匯入資料:

INSERT INTO <table_name> [(<col_name> [, <col_name>])]
VALUES [(<value> [, <value>])];

示例

insert into articles_test (id, author, title, body, comment, create_time) values(0, '張三', '浙江省杭州市春天美景推薦', '浙江省杭州市擁有美麗的西湖,是全國有名的風景勝地,春天的景色尤其迷人', '好地方', '2018-02-01 10:10:13');

insert into articles_test (id, author, title, body, comment, create_time) values(1, '張三', '江西九江夏天美麗景色', '廬山風景區坐落於江西九江,北瀕長江,南傍鄱陽湖,素有“匡廬奇秀甲天下山”之美稱。', '好地方', '2018-09-13 10:10:13');

insert into articles_test (id, author, title, body, comment, create_time) values(2, '李四', 'x省秋天美麗景色', '那山,那水,那滿眼的綠,那不同於紅磚白牆的色彩在華山燁燁生輝', '好地方', '2018-09-30 10:10:13');

insert into articles_test (id, author, title, body, comment, create_time) values(3, '王五', '《建國大業》簡介', '中華人民共和國位於亞洲東部,太平洋西岸,是工人階級領導的、以工農聯盟為基礎的人民民主專政的社會主義國家,成立於1949年(己丑年)10月1日', '國富民強', '2018-10-18 10:10:13');

insert into articles_test (id, author, title, body, comment, create_time) values(4, '王五', '地理資訊大全', '共和國山地、高原和丘陵約佔陸地面積的67%,盆地和平原約佔陸地面積的33%。山脈多呈東西和東北一西南走向', '國富民強', '2018-09-30 23:10:13');

insert into articles_test (id, author, title, body, comment, create_time) values(5, '李四', '浙江杭州秋天哪裡風景最美', '杭州一年中最美的季節不是春天嗎?這個我不辯駁,也承認杭州的春天確實很美,我也很喜歡春天這個季節的杭州城。但是,和火紅般的秋季比起來,我還是更喜歡秋天的杭州城。', '好地方', '2018-02-01 10:10:13');

insert into articles_test (id, author, title, body, comment, create_time) values(9, '李四', '浙江杭州千島湖', '梅峰島是千島湖風景區登高觀湖攬勝的最佳處,素有“不上梅峰觀群島,不識千島真面目”', '好地方', '2018-02-01 10:10:13');

查詢語法

查詢語法

AnalyticDB支援通過以下語法進行全文檢索:

SELECT <col_name>
FROM <table_name>
WHERE match(<col_name> [, <col_name>]) against('<words>')

含義為:在已經建立全文索引的col_name列中,檢索words關鍵詞。

引數說明:

  • match(<col_name> [, <col_name>])的引數,要求是已經在建表語句中建立了全文索引的列的名字,可以填寫一個列名,也可以填寫多個列名。比如 match(body)表示只在body這一列中進行檢索; match(title, body)表示在
    title、body兩列中分別進行檢索。
  • against('<words>')的引數為需要進行檢索的關鍵詞,比如against('浙江省杭州市')表示要檢索“浙江省杭州市”。

示例

-- 查詢所有資料是否可見
select * from articles_test;

-- 在body中檢索“浙江省杭州市”
select * from articles_test where match(body) against('浙江省杭州市');

-- 在title、body兩列中檢索“春天”
select * from articles_test where match(title, body) against('春天');

更多關鍵詞檢索方式

AnalyticDB支援多種關鍵詞檢索方式:

  • 基本查詢
  • 按近似度排序
  • 結果集過濾
  • 多列查詢
  • 短語查詢、精確匹配
  • 邏輯操作符AND OR NOT
  • 結構化、非結構化聯合檢索
  • 高階SQL語法:結構化、非結構化GROUP BY, JOIN, UNION

基本查詢

ADS支援“開箱即用”的簡單全文檢索查詢。

值得注意的是:未帶ORDER BY的情況下,返回結果不會按照近似度排序(若需排序請參見“按近似度排序”一節)。

-- 基本查詢: 在title這一列中檢索‘浙江省’關鍵字,返回所有命中關鍵字的結果行;

SELECT id, title, author, body 
FROM articles_test 
WHERE match(title) against ('浙江省')
LIMIT 100;

-- 基本查詢: 在title這一列中檢索‘浙江省杭州市’關鍵字,返回所有命中關鍵字的結果行;

SELECT id, title, author, body 
FROM articles_test 
WHERE match(title) against ('浙江省杭州市')
LIMIT 100;

-- 基本查詢: 在title這一列中檢索‘浙江省 杭州市’關鍵字,返回所有命中關鍵字的結果行;

SELECT id, title, author, body 
FROM articles_test 
WHERE match(title) against ('浙江省 杭州市')
LIMIT 100;

按近似度排序

SQL語義規定在不帶ORDER BY的情況下,不會按照近似度排序。如果需要將所有命中結果按照近似度從高到低排序,則使用如下SQL語法。

-- 近似度排序:如果需要將結果按照近似度從高到低排序,則加上ORDER BY DESC

SELECT id, title, author, body 
FROM articles_test 
WHERE match(title) against ('浙江省杭州市')
ORDER BY match(title) against ('浙江省杭州市') DESC
LIMIT 100;

結果集過濾

全文檢索會召回所有跟關鍵詞近似的結果。在某些資料量很大的場景中,命中關鍵詞的結果集可能也很大,但是往往只需要取出近似度較高的部分結果。

AnalyticDB提供了結果集過濾的功能,使用如下語法取出近似度排在前(1-N)的結果:

WHERE match(<col_name> [, <col_name>]) against('<words>') > N 

示例

-- 結果集過濾:如果需要過濾掉近似度較低的結果行,則在WHERE中進行限定。
-- 如下例子中where match() against() > 0.9 表示只取近似度排在前10%的結果,過濾掉了90%的低近似度結果。

SELECT id, title, author, body 
FROM articles_test 
WHERE match(title) against ('浙江省杭州市') > 0.9
ORDER BY match(title) against ('浙江省杭州市') DESC
LIMIT 100;

多列查詢

AnalyticDB支援同時在多個全文索引列中進行檢索。

-- 多列查詢: 在title,body兩列中同時檢索‘浙江省杭州市’關鍵字,返回近似度排在前10%的結果行,並且將結果行按照近似度逆序排列。

SELECT id, title, author, body 
FROM articles_test 
WHERE match(title,body) against ('浙江省杭州市') > 0.9
ORDER BY match(title, body) against ('浙江省杭州市') DESC
LIMIT 100;

短語查詢、精確匹配

預設情況下,AnalyticDB全文檢索會對詞語進行分詞後,再進行檢索。比如檢索“中華人民共和國”會被分詞為“中華”、“人民”、“共和國”三個詞分別檢索。但是某些特殊情況下,可能需要完全精確的短語匹配。比如只希望返回完全精確匹配“中華人民共和國”的結果,而不希望返回分詞後的檢索結果,則使用短語查詢語法。

語法格式為:在檢索關鍵詞上加雙引號。

-- 如下兩個例子進行對比:
-- 基本查詢:分詞後再檢索。注意關鍵詞的寫法,沒有雙引號。

SELECT id, title, author, body 
FROM articles_test 
WHERE match(body) against ('中華人民共和國') > 0.9
ORDER BY match(body) against ('中華人民共和國') DESC
LIMIT 100;

-- 短語查詢:精確匹配,不會做分詞處理。注意關鍵詞的寫法,有雙引號。

SELECT id, title, author, body 
FROM articles_test 
WHERE match(body) against ('"中華人民共和國"') > 0.9
ORDER BY match(body) against ('"中華人民共和國"') DESC
LIMIT 100;

邏輯操作符 AND OR NOT

AnalyticDB支援利用邏輯操作符對結果進行控制。目前支援的邏輯操作符包括:AND OR NOT

其中AND表示要求操作符兩邊的關鍵詞都必須出現。OR表示操作符兩邊的關鍵詞出現一個即可。NOT表示右側的關鍵詞不能出現。

語法為:<word1> AND/OR/NOT <word2>

注意:1)AND/OR/NOT必須大寫;2)AND/OR/NOT兩邊必須有空格。

-- 要求‘浙江省’,‘杭州市’都必須出現。
SELECT id, title, author, body 
FROM articles_test 
WHERE match(body) against ('浙江省 AND 杭州市') > 0.9
ORDER BY match(body) against ('浙江省 AND 杭州市') DESC
LIMIT 100;

-- 要求‘浙江省’,‘杭州市’出現一個即可。效果等同於如下寫法:'浙江省杭州市', '浙江省 杭州市'
SELECT id, title, author, body 
FROM articles_test 
WHERE match(body) against ('浙江省 OR 杭州市') > 0.9
ORDER BY match(body) against ('浙江省 OR 杭州市') DESC
LIMIT 100;

-- 要求‘浙江省’一定不能出現
SELECT id, title, author, body 
FROM articles_test 
WHERE match(body) against ('杭州市 NOT 浙江省') > 0.9
ORDER BY match(body) against ('杭州市 NOT 浙江省') DESC
LIMIT 100;

結構化、非結構化聯合檢索

AnalyticDB支援對結構化列、非結構化列進行聯合條件檢索。

-- 例如: 要求查詢create_time在20180201-20180930之間的、body命中“浙江省杭州市”、且comment不為空的資料行。

SELECT id, title, author, body 
FROM articles_test 
WHERE create_time > '2018-02-01 00:00:00' 
        AND create_time < '2018-09-30 24:00:00'
        AND match(body) against ('浙江省杭州市') > 0.9
        AND comment is not null
ORDER BY match(body) against ('浙江省杭州市') DESC
LIMIT 100;

-- 例如: 要求在body中檢索“浙江省杭州市”, 且在author中檢索“張三”。

SELECT id, author, body 
FROM articles_test 
WHERE match(body) against ('浙江省杭州市') > 0.9
        AND match(author) against('張三') > 0.9
ORDER BY match(body) against ('浙江省杭州市') DESC, match(author) against('張三') DESC
LIMIT 100;

高階SQL語法:結構化、非結構化融合GROUP BY, JOIN, UNION

-- 分組

SELECT author, body, max(match(body) against ('浙江省杭州市')) as score
FROM articles_test 
WHERE match(body) against ('浙江省杭州市') > 0.9
GROUP BY author, body
ORDER BY score DESC
LIMIT 100;

-- 表連線: 在文章表articles_test中檢索“浙江省杭州市”, 在作者資訊表author_info中檢索“張三”,並且利用id列將兩表進行join。

CREATE TABLE author_info (
  id bigint COMMENT '',
  name varchar COMMENT '',
  addr varchar COMMENT '',
  FULLTEXT INDEX name_fulltext (name),
  FULLTEXT INDEX addr_fulltext (addr),
  PRIMARY KEY (id)
)
PARTITION BY HASH KEY(id)
PARTITION NUM 8
CLUSTERED BY (id)
TABLEGROUP test_group
OPTIONS (UPDATETYPE='realtime')
COMMENT '';

insert into author_info(id, name, addr) values(0, '張三', '湖南省張家界市武陵源區');

SELECT articles_test.id, articles_test.title, author_info.name, author_info.addr
FROM articles_test 
    JOIN author_info
    ON articles_test.id = author_info.id 
WHERE
    match (articles_test.body) against ('浙江省杭州市')
    AND match(author_info.name) against ('張三')
    AND articles_test.create_time between '2018-01-01 00:00:00' and '2018-09-30 00:00:00';


-- 合併

SELECT id, title 
FROM articles_test 
WHERE
    match (articles_test.body) against ('浙江省杭州市')
UNION ALL
SELECT id, addr 
FROM author_info
WHERE
    match(author_info.name) against ('張三');