本文基於資料庫-ElasticSearch入門(索引、檔案、查詢),假設讀者已學會安裝ES,使用Postman和某語言的包或模組來對索引和檔案進行基本的增刪改查。
Elasticsearch 是一個開源的搜尋引擎,建立在一個全文搜尋引擎庫 Apache Lucene基礎之上。Elasticsearch 也是使用** Java** 編寫的,它的內部使用 Lucene 做索引與搜尋,但是它的目的是使全文檢索變得簡單, 通過隱藏 Lucene 的複雜性,取而代之的提供一套簡單一致的 RESTful API。
curl "http://localhost:9200/"
{
"name" : "DESKTOP-BT64DM0",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "Xk7sJl7OSei9DIyrn1G-vg",
"version" : {
"number" : "7.10.0",
"build_flavor" : "default",
"build_type" : "zip",
"build_hash" : "51e9d6f22758d0374a0f3f5c6e8f3a7997850f96",
"build_date" : "2020-11-09T21:30:33.964949Z",
"build_snapshot" : false,
"lucene_version" : "8.7.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
啟動後存取9200埠,可以看到ES版本,叢集名稱,lucence版本等內容。
兩個 Java 使用者端都是通過 9300 埠並使用 Elasticsearch 的原生傳輸協定和叢集互動。叢集中的節點通過埠 9300 彼此通訊。如果這個埠沒有開啟,節點將無法形成一個叢集。
可以建立索引時,攜帶請求體body,設定分片,mapping等
類似分表,進行容量擴充套件。ES可以將一個索引的分片放到不同的節點上,這樣可以進行快速的分散式搜尋。總的來說,分片可以
在一些情況下,可能導致某個節點/分片處於離線狀態,為了保證出現故障時不影響服務,提出了副本,進行容災備份,提供高可用性。
master節點完成分配主分片和副本的過程。
mapping是處理資料的方式和規則的限制。如欄位的資料型別、是否被索引、分析器等。
為了對新手友好一些,可以直接建立index,不用指定欄位及型別,ES自動新增。
瞭解欄位型別之後,給不同的欄位自定義資料型別,建立索引時進行指定。
PUT my-index
{
"mappings": {
"properties": {
"city": {
"type": "text",
"fields": {
"raw": {
"type": "keyword"
}
}
}
}
}
}
properties新增欄位,fields使一個欄位在不同型別搜尋時是否可分析
city欄位全文檢索
city.raw欄位是city的keyword版本,可被用於排序和聚合操作。
接下來先了解欄位等概念,之後再配合搜尋對對映進行深入理解。
使用 JSON 構造了一個請求。包含了filter range過濾器。
在全文檢索情況下,對text等型別分詞,方便建立倒排索引。常見的分詞器有
按照相關性得分排序,一般使用TF-IDF演演算法(見參考,本文主要還是在ES實踐方面,演演算法不贅述),通過_score返回得分
ES,you know, for search, 搜尋才是重點!!!
索引heros,欄位及型別如下:
name | age | role | birthday | hobby | sentence | |
---|---|---|---|---|---|---|
大喬 | 18 | 輔助 | 2003-11-10 | daqiao@163.com | 寫詩 畫畫 | 詩是自由的載體 |
小喬 | 19 | 法師 | 2002-01-20 | xiaoqiao@sina.com | 畫畫 唱歌 | Whenever you need me, I’ll be here. |
孫策 | 25 | 坦克 | 1996-11-10 | sunce@163.com | 畫畫 唱歌 | 我向往詩和遠方,也不會忘記她和故鄉 |
周瑜 | 23 | 法師 | 1998-01-20 | zhouyu@sina.com | 寫詩 畫畫 | Whenever you are in trouble,I’m always near. |
劉備 | 30 | 打野 | 1991-10-20 | liubei@qq.com | 兵法 武器 | Shi wo bu tai dong |
孫尚香 | 26 | 射手 | 1995-10-20 | 兵法 化妝 | 詩我不太懂 |
PUT /heros
這裡使用的Kibana的DevTools,如果你看了ES系列第一篇文章,有白嫖騰訊雲的ES叢集,可以點選視覺化設定,給Kibana設定公網白名單即可,由於我前面的文章還沒有介紹Kibana的使用,你可以繼續使用Postman、curl或elasticsearch-head外掛來發起請求。
檢視setting和mapping情況
GET /heros?pretty
新增一個檔案
POST /heros/_doc/1001
{
"name":"大喬",
"age":18,
"role":"輔助",
"birthday":"2003-11-10",
"mail":"daqiao@163.com",
"hobby":"寫詩 畫畫",
"sentence":"詩是自由的載體"
}
結果如下
再次查詢mapping
可以看到ES自動新增了型別,但是與我們要求的不符合。有些不會自動分詞,無法進行後序的搜尋。
刪除索引,再次新增
PUT /heros
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"name":{
"type": "keyword"
},
"age":{
"type": "byte"
},
"role":{
"type": "keyword"
},
"mail":{
"type":"text"
},
"birthday":{
"type":"date"
},
"hobby":{
"type": "text"
},
"sentence":{
"type":"text"
}
}
}
}
之後新增檔案,其他英雄的放在附錄了,最終的索引應該如下圖所示:
結構化搜尋(Structured search) 是指有關探詢那些具有內在結構資料的過程。比如日期、時間和數位都是結構化的:它們有精確的格式,我們可以對這些格式進行邏輯操作。
在結構化查詢中,要麼存於集合之中,要麼存在集合之外。結構化查詢不關心檔案的相關度或評分;它簡單的對檔案包括或排除處理。
我們首先來看最為常用的 term 查詢, 可以用它處理數位(numbers)、布林值(Booleans)、日期(date)等。
注意:ES5.0後,已經沒有string型別了
警告:儘量不要用於text型別欄位
查詢角色是「法師」的英雄
GET /heros/_search
{
"query":{
"term":{
"role":"法師"
}
}
}
結果如下圖所示
多個精確值terms
查詢角色是「法師」或「射手」的英雄
GET /heros/_search
{
"query":{
"terms":{
"role":["法師","射手"]
}
}
}
結果如圖所示
可以看到,多了射手角色的英雄。
{
"range":{
"field_name":{
},
}
}
對欄位進行範圍過濾,常用的如下
查詢19<=age<25的英雄
GET /heros/_search
{
"query": {
"range":{
"age":{
"gte":19,
"lt":25
}
}
}
}
結果如下圖所示
將多個過濾器進行組組合
{
"bool" : {
"must" : [],
"must_not" : [],
"should" : [],
"filter":[],
}
}
查詢角色是法師或輔助,年齡必須小於20,郵箱不能是新浪郵箱的英雄
GET /heros/_search
{
"query": {
"bool": {
"must": {
"range":{
"age":{
"lt":20
}
}
},
"must_not":
{
"match":{"mail":"@sina.com"}
},
"should": [
{
"term": {"role": "法師"}
},
{
"term":{"role":"輔助"}
}
]
}
}
}
看前面的資料可以發現,就剩大喬了,結果如下圖所示
查詢有郵箱的英雄
GET /heros/_search
{
"query": {
"exists": {
"field": "mail"
}
}
}
結果如下圖所示
那麼,如何查詢不存在郵箱的英雄呢?之前有missing,現在不支援了,可以使用must_not進行巢狀
GET /heros/_search
{
"query": {
"bool": {
"must_not": {
"exists":{
"field": "mail"
}
}
}
}
}
結果如下圖所示
如 term 或 fuzzy 這樣的底層查詢不需要分析階段,它們對單個詞項進行操作。
像 match 或 query_string 這樣的查詢是高層查詢,它們瞭解欄位對映的資訊
查詢sentence中含詩的英雄
GET /heros/_search
{
"query": {
"match": {
"sentence": "詩"
}
}
}
結果如下圖所示
可以看到,評分語句更短的評分更高
多詞搜尋情況下
查詢sentence中含「我 詩」的英雄
GET /heros/_search
{
"query": {
"match": {
"sentence": "我 詩"
}
}
}
結果如下圖所示
可以看到有些只包含我或詩的內容也出來了,雖然排名落後,如何做到且呢,前面使用了must,這裡使用operator實現
GET /heros/_search
{
"query": {
"match": {
"sentence": {
"query": "我 詩",
"operator": "and"
}
}
}
}
結果如下圖所示
查詢sentence中必須包含"Whenever",有"in"或者"be"的英雄
GET /heros/_search
{
"query": {
"bool": {
"must": [
{"match": {
"sentence": "Whenever"
}}
],
"should": [
{ "match": { "sentence": "in" }
},
{ "match": { "sentence": "be" }}
]
}
}
}
結果如下圖所示
現要求含in的權重更高,也就是提高_score來提高搜尋排名
boost預設為1,通過增加in的boost來提高in的排名
GET /heros/_search
{
"query": {
"bool": {
"must": [
{"match": {
"sentence": "Whenever"
}}
],
"should": [
{ "match": {
"sentence": {
"query": "in",
"boost": 2
}
}
},
{ "match": { "sentence": "be" }}
]
}
}
}
結果如下圖所示
前面已經進行了簡單的多字串搜尋,不過,還有一些多欄位時複雜的搜尋情況。
查詢愛好有詩,sentence(隨便起的名字,可以理解為個性簽名或一句話介紹)中有詩或她的英雄
GET /heros/_search
{
"query": {
"bool": {
"should": [
{ "match": { "hobby": "詩" }},
{ "match": { "sentence": "詩 她" }}
]
}
}
}
結果如下圖所示
可以看到,第二個結果是我們更想得到的。bool會打兩次分,再除以語句總數2,第一個結果hobby和sentence都有詩,導致第一個結果就靠前了,由於hobby和sentence的競爭關係,所以需要找到最佳匹配欄位。
使用dis_max來得到想要的結果
GET /heros/_search
{
"query": {
"dis_max": {
"queries": [
{ "match": { "hobby": "詩" }},
{ "match": { "sentence": "詩 她" }}
]
}
}
}
結果如下圖所示
tips:想要在bool和dis_max之間,可以使用tie_breaker引數,請讀者自行深入瞭解。
查詢hobby或sentence中含詩的英雄,也就是對hobby sentence做同一搜尋,如果寫多個match會比較繁瑣,可以採用multi_match,欄位使用列表的方式填寫多個即可。
GET /heros/_search
{
"query": {
"multi_match": {
"query": "詩",
"fields": ["hobby","sentence"]
}
}
}
結果如下圖所示
hobby和sentence都含詩的會排名靠前
即只輸入一部分,也能匹配到,最經典的就是邊輸入邊搜尋,也。
現在很多搜尋引擎都有使用者邊輸入邊提示的功能,不必等使用者Enter,提高了使用者體驗
使用者查詢sentence,輸入了when,查詢此時的下拉框的結果
GET /heros/_search
{
"query": {
"match_phrase_prefix": {
"sentence": {
"query": "When"
}
}
}
}
結果如下圖所示
包含兩個萬用字元"?「和」*",? 匹配任意字元, * 匹配 0 或多個字元
搜尋姓孫的英雄
GET /heros/_search
{
"query": {
"wildcard": {
"name": "孫*"
}
}
}
結果如下圖所示
正規表示式更加的豐富,包含數位、特殊字元等
搜尋郵箱含s、n,s在n前面的英雄
GET /heros/_search
{
"query": {
"regexp": {
"mail": "s.*n.*"
}
}
}
結果如下圖所示
sunce符合,新浪郵箱也符合。
本文講了一些基礎概念,深入研究了一些搜尋(拋轉引玉,官網還有很多搜尋方式),本來想寫叢集的,白嫖騰訊雲的只能固定三個節點,沒法演示擴容之類的,下篇文章再說一下叢集。
練習
查詢角色是「坦克」的英雄?
查詢年齡>18的「法師」英雄?
查詢姓"孫"的且名字是兩個字的英雄?
POST /heros/_doc/1002
{
"name":"小喬",
"age":19,
"role":"法師",
"birthday":"2002-01-20",
"mail":"xiaoqiao@sina.com",
"hobby":"畫畫 唱歌",
"sentence":"Whenever you need me, I'll be here."
}
POST /heros/_doc/1003
{
"name":"孫策",
"age":25,
"role":"坦克",
"birthday":"1996-11-10",
"mail":"sunce@163.com",
"hobby":"畫畫 唱歌",
"sentence":"我向往詩和遠方,也不會忘記她和故鄉"
}
POST /heros/_doc/1004
{
"name":"周瑜",
"age":23,
"role":"法師",
"birthday":"1998-01-20",
"mail":"zhouyu@sina.com",
"hobby":"寫詩 畫畫",
"sentence":"Whenever you are in trouble,I'm always near."
}
POST /heros/_doc/1005
{
"name":"劉備",
"age":30,
"role":"打野",
"birthday":"1991-10-20",
"mail":"liubei@qq.com",
"hobby":"兵法 武器",
"sentence":"Shi wo bu tai dong"
}
POST /heros/_doc/1006
{
"name":"孫尚香",
"age":26,
"role":"射手",
"birthday":"1995-10-20",
"hobby":"兵法 化妝",
"sentence":"詩我不太懂"
}
ES權威指南
ES Guide
ES中文社群
騰訊-ES服務產品檔案
IK分詞器
ICU分詞器
smartcn分詞器
TF-IDF與餘弦相似性的應用(一):自動提取關鍵詞
更多ELK相關內容:資料庫-ElasticSearch學習筆記_lady_killer9的部落格-CSDN部落格
喜歡本文的請動動小手點個贊,收藏一下,有問題請下方評論,轉載請註明出處,並附有原文連結,謝謝!
如有侵權,請及時聯絡。如果您感覺有所收穫,自願打賞,可選擇支付寶18833895206(小於),您的支援是我不斷更新的動力。