1. 程式人生 > >Elasticsearch系列---結構化搜尋

Elasticsearch系列---結構化搜尋

概要

結構化搜尋針對日期、時間、數字等結構化資料的搜尋,它們有自己的格式,我們可以對它們進行範圍,比較大小等邏輯操作,這些邏輯操作得到的結果非黑即白,要麼符合條件在結果集裡,要麼不符合條件在結果集之外,沒有那種相似的概念。

前言

結構化搜尋將會有大量的搜尋例項,我們將"音樂APP"作為主要的案例背景,去開發一些跟音樂APP相關的搜尋或資料分析,有助力於我們理解實戰的目標,順帶鞏固一下學習的知識。

我們將一首歌需要的欄位暫定為:
| name | code | type | remark |
| :---- | :--: | :--: | -----: |
| ID | id | keyword | 文件ID |
| 歌手 | author | text | |
| 歌曲名稱 | name | text | |
| 歌詞 | content | text | |
| 語種 | language | text | |
| 標籤 | tags | text | |
| 歌曲時長 | length | long | 記錄秒數 |
| 喜歡次數 | likes | long | 點選喜歡1次,自增1 |
| 是否釋出 | isRelease | boolean | true已釋出,false未釋出 |
| 釋出日期 | releaseDate | date | |

我們手動定義的索引mapping資訊如下:

PUT /music
{
  "mappings": {
      "children": {
        "properties": {
          "id": {
            "type": "keyword"
          },
          "author_first_name": {
            "type": "text",
            "analyzer": "english"
          },
          "author_last_name": {
            "type": "text",
            "analyzer": "english"
          },
          "author": {
            "type": "text",
            "analyzer": "english",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "name": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "content": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "language": {
            "type": "text",
            "analyzer": "english",
            "fielddata": true
          },
          "tags": {
            "type": "text",
            "analyzer": "english"
          },
          "length": {
            "type": "long"
          },
          "likes": {
            "type": "long"
          },
          "isRelease": {
            "type": "boolean"
          },
          "releaseDate": {
            "type": "date"
          }
        }
      }
  }
}

我們預先匯入一批資料進去:

POST /music/children/_bulk
{ "index": { "_id": 1 }}
{ "id" : "34116101-7fa2-5630-a1a4-1735e19d2834", "author_first_name":"Peter", "author_last_name":"Gymbo", "author" : "Peter Gymbo", "name": "gymbo", "content":"I hava a friend who loves smile, gymbo is his name", "language":"english", "tags":["enlighten","gymbo","friend"], "length":53, "likes": 5, "isRelease":true, "releaseDate": "2019-12-20" }
{ "index": { "_id": 2 }}
{ "id" : "34117101-54cb-59a1-9b7a-82adb46fa58d", "author_first_name":"John", "author_last_name":"Smith", "author" : "John Smith", "name": "wake me, shark me", "content":"don't let me sleep too late, gonna get up brightly early in the morning", "language":"english", "tags":["wake","early","morning"], "length":55, "likes": 8,"isRelease":true, "releaseDate": "2019-12-21" }
{ "index": { "_id": 3 }}
{ "id" : "34117201-8d01-49d4-a495-69634ae67017", "author_first_name":"Jimmie", "author_last_name":"Davis", "author" : "Jimmie Davis", "name": "you are my sunshine", "content":"you are my sunshine, my only sunshine, you make me happy, when skies are gray", "language":"english", "tags":["sunshine","happy"], "length":65,"likes": 12, "isRelease":true, "releaseDate": "2019-12-22" }
{ "index": { "_id": 4 }}
{ "id" : "55fa74f7-35f3-4313-a678-18c19c918a78", "author_first_name":"Peter", "author_last_name":"Raffi", "author" : "Peter Raffi", "name": "brush your teeth", "content":"When you wake up in the morning it's a quarter to one, and you want to have a little fun You brush your teeth", "language":"english", "tags":"teeth", "length":45,"likes": 17, "isRelease":true, "releaseDate": "2019-12-22" }
{ "index": { "_id": 5 }}
{ "id" : "1740e61c-63da-474f-9058-c2ab3c4f0b0a", "author_first_name":"Jean", "author_last_name":"Ritchie", "author" : "Jean Ritchie", "name": "love somebody", "content":"love somebody, yes I do", "language":"english", "tags":"love", "length":38, "likes": 3,"isRelease":true, "releaseDate": "2019-12-22" }

精確值查詢

我們根據文件的mapping設計,可以按ID、按日期進行查詢。

根據ID搜尋歌曲

GET /music/children/_search
{
    "query" : {
        "constant_score" : { 
            "filter" : {
                "term" : { 
                    "id" : "34116101-7fa2-5630-a1a4-1735e19d2834"
                }
            }
        }
    }
}

注意ID建立時,型別是指定為keyword,這樣ID在索引時不會進行分詞。如果型別為text,UUID值在索引時會分詞,這樣反而查不到結果了。

按日期搜尋歌曲

GET /music/children/_search
{
    "query" : {
        "constant_score" : { 
            "filter" : {
                "term" : { 
                    "releaseDate" : "2019-12-21"
                }
            }
        }
    }
}

按歌曲時長搜尋

GET /music/children/_search
{
    "query" : {
        "constant_score" : { 
            "filter" : {
                "term" : { 
                    "length" : 53
                }
            }
        }
    }
}

搜尋已釋出的歌曲

GET /music/children/_search
{
    "query" : {
        "constant_score" : { 
            "filter" : {
                "term" : { 
                    "isRelease" : true
                }
            }
        }
    }
}

以上3個小例子可以發現:準確值搜尋對keyword、日期、數字、boolean值天然支援。

組合過濾

前面的4個小例子都是單條件過濾的,實際的需求肯定會有多個條件,不過萬變不離其宗,再複雜的搜尋需求,也是由一個一個的基礎條件複合而成的,我們來看幾個簡單的組合過濾的例子。

複習一下之前學過的邏輯:

  • bool 組合多個條件,可以巢狀
  • must 必須匹配
  • should 可以匹配(類似於or,多個條件在should裡)
  • must_not 必須不匹配

搜尋釋出日期為2019-12-20,或歌曲ID為2a8f4288-c0a9-5c9b-8f99-67339b66f4c0,但釋出日期不能是2019-12-21的歌曲

GET /music/children/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "bool": {
          "should": [
            {"term":{
              "releaseDate":"2019-12-20"
            }},
            {"term":{
              "id":"2a8f4288-c0a9-5c9b-8f99-67339b66f4c0"
            }}
          ],
          "must_not": {
          "term": {
            "releaseDate":"2019-12-21"
          }
        }
        }
      }
    }
  }
}

搜尋歌曲ID為2a8f4288-c0a9-5c9b-8f99-67339b66f4c0,或者是歌曲ID為34116101-7fa2-5630-a1a4-1735e19d2834而且釋出日期為2019-12-20的帖子

GET /music/children/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "bool": {
          "should": [
            {"term":{
              "id":"2a8f4288-c0a9-5c9b-8f99-67339b66f4c0"
            }},
            {
              "bool": {
                "must" : [
                  {
                  "term" : {
                "id":"34116101-7fa2-5630-a1a4-1735e19d2834"
                  }},
                 { "term" : {
                    "releaseDate":"2019-12-20"
                  }}
                ]
              }
            }
          ]
        }
        }
      }
    }
  }

多值搜尋

使用語法terms,可以同時搜尋多個值,類似mysql的in語句。

GET /music/children/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "terms": {
          "id": [
            "34116101-7fa2-5630-a1a4-1735e19d2834",
            "99268c7e-8308-569a-a975-bbce7d3f9a8e"
          ]
        }
      }
    }
  }
}

範圍查詢

針對Long型別和date型別的資料,是支援範圍查詢的,使用gt、lt、gte、lte來完成範圍的判斷。與mysql的>、<、>=、<=以及between...and異曲同工。

搜尋時長在45-60秒之間的歌曲

對Long型別的範圍查詢,直接使用範圍表示式:

GET /music/children/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "length": {
            "gte": 45,
            "lte": 60
          }
        }
      }
    }
  }
}

日期的範圍搜尋

針對日期的範圍搜尋,除了直接寫日期,加上常規的範圍表示式之外,還可以使用+1d、-1d表示對指定日期的加減,如"2019-12-21||-1d"表示"2019-12-20",也可以使用now-1d表示昨天,挺有趣。

給個示例:搜尋2019-12-21前一天新發布的歌曲

GET /music/children/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "releaseDate" :{
          "gt":"2019-12-21||-1d"
        }
      }
    }
  }
}
}

Null值處理

倒排索引在建立時,是不接受空值的,這就意味著null,[],[null]這些各種形式的null值,不無法存入倒排索引的,那這樣怎麼辦?

Elasticsearch提供了兩種查詢,類似於mysql的is not null和not exists。

存在查詢

exists查詢,會返回那些指定欄位有值的文件,與mysql的is not null類似。

案例中的tags欄位,就是一個選填項,有些記錄可能是null值,如果我需要查詢所有的tags值的記錄,請求如下:

GET /music/children/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "exists": {
          "field": "tags"
        }
      }
    }
  }
}

缺失查詢

缺失查詢原來是有關鍵字missing表示,效果與exists相反,語法上與mysql的is null類似,但6.x版本就已經廢棄了,我們可以改用must not + exists實現相同的效果。

還是使用tags欄位為例,查詢tags為空的文件:

GET /music/children/_search
{
  "query": {
    "bool": {
      "must_not": {
        "exists": {
          "field": "tags"
        }
      }
    }
  }
}

filter快取

過濾器為什麼效率那麼高?除了本身的設計集合來達到高效過濾之外,還將查詢結果適當地快取化。

filter執行原理

我們瞭解一下Elasticsearch對過濾器的簡單操作:

  1. 根據fitler條件查詢匹配的文件,獲取document list。如果有多個過濾條件且涉及多個欄位,那麼就會有多個document list,document list是按倒排索引來的。
  2. 根據document list構建bitset(包含0或1的陣列),匹配了是1,沒匹配上為0,如[1,0,0,0]。
  3. 迭代所有的bitset,從最稀疏的開始(可以排除到大量的文件),取陣列相同位置所有值為1的記錄。
  4. 將bitset快取在記憶體中,用於提高效能。

filter比query好處是會caching,下次不用查倒排索引,filter大部分情況下在query之前執行query會計算doc對搜尋條件的relevance score,還會根據這個score去排序
filter簡單過濾出想要的資料,不計算relevance score,也不排序

filter快取

快取條件
  1. 最近的256個filter中,某個filter超過一定次數(次數不固定),就會自動快取這個filter對應的bitset。
  2. filter針對小segment獲取的結果,可以不快取,segment<1000條或segment大小<index總大小的 3%。原因是資料量小,重新掃描很快,太小的segment在後臺會自動合併到大的segment中,快取意義不大
快取更新

快取的更新非常智慧,增量更新的方式,如果有document新增或修改時,會將新文件加入bitset,而不是刪除快取或整個重新計算。

小結

本篇前半部分使用了大量的示例,可以快速閱讀,後面介紹了filter的過濾原理及快取處理機制,可以瞭解一下,謝謝。

專注Java高併發、分散式架構,更多技術乾貨分享與心得,請關注公眾號:Java架構社群
可以掃左邊二維碼新增好友,邀請你加入Java架構社群微信群共同探討技術

相關推薦

Elasticsearch系列---結構搜尋

概要 結構化搜尋針對日期、時間、數字等結構化資料的搜尋,它們有自己的格式,我們可以對它們進行範圍,比較大小等邏輯操作,這些邏輯操作得到的結果非黑即白,要麼符合條件在結果集裡,要麼不符合條件在結果集之外,沒有那種相似的概念。 前言 結構化搜尋將會有大量的搜尋例項,我們將"音樂APP"作為主要的案例背景,去開發一

elasticsearch 深入 —— 結構搜尋

結構化搜尋 結構化搜尋(Structured search) 是指有關探詢那些具有內在結構資料的過程。比如日期、時間和數字都是結構化的:它們有精確的格式,我們可以對這些格式進行邏輯操作。比較常見的操作包括比較數字或時間的範圍,或判定兩個值的大小。 文字也可以是結構化的。如

ElasticSearch進階(一)結構搜尋_在案例中使用term filter來搜尋資料

1、根據使用者ID、是否隱藏、帖子ID、發帖日期來搜尋帖子 (1)插入一些測試帖子資料 初步來說,就先搞4個欄位,因為整個es是支援json document格式的,所以說擴充套件性和靈活性非常之好。

ElasticStack學習(九):深入ElasticSearch搜尋之詞項、全文字、結構搜尋及相關性算分

一、基於詞項與全文的搜尋   1、詞項     Term(詞項)是表達語意的最小單位,搜尋和利用統計語言模型進行自然語言處理都需要處理Term。     Term的使用說明:     1)Term Level Query:Term Query、Range Query、Exists Query

ElasticSearch常用結構搜索

rop tar 情況 test art ice 都是 其中 ngs 最近,需要用到ES的一些常用的結構化搜索命令,因此,看了一些官方的文檔,學習了一下。結構化查詢指的是查詢那些具有內在結構的數據,比如日期、時間、數字都是結構化的。 它們都有精確的格式,我們可以對這些數據進行

第九章:深入搜尋--結構搜尋

一.精確搜尋,多個精確搜尋  1.term 查詢     term 查詢可以用它處理數字(numbers)、布林值(Booleans)、日期(dates)以及文字(text). 使用bulk建立檔案文件  POST /my_store/products/_bulk {

elasticsearch系列四:搜尋詳解(搜尋API、Query DSL)

{  "took": 60,  "timed_out": false,  "_shards": {    "total": 5,    "successful": 5,    "skipped": 0,    "failed": 0  },  "hits": {    "total": 1000,    "m

Elasticsearch系列---深入全文搜尋

概要 本篇介紹怎樣在全文欄位中搜索到最相關的文件,包含手動控制搜尋的精準度,搜尋條件權重控制。 手動控制搜尋的精準度 搜尋的兩個重要維度:相關性(Relevance)和分析(Analysis)。 相關性是評價查詢條件與結果的相關程度,並對相關程度進行排序,一般使用TF/IDF方法。 分析是指將索引文件與查詢條

ElasticSearch 結構搜索全文

一個 http tps 文本查詢 bar asi 這樣的 listitem ria   1、介紹     上篇介紹了搜索結構化數據的簡單應用示例,現在來探尋 全文搜索(full-text search) :怎樣在全文字段中搜索到最相關的文檔。     全文搜索兩個最重要

Hulu機器學習問題與解答系列 | 二十二:特征工程—結構數據

實現 adk n) 過程 結果 點擊 推薦算法 cti 特征工程 聽說最近冒出的大批呱兒子個個都是撐著眼皮也要看書的無眠小青蛙。我們學習Machine Learning的腳步又怎能停下來?動動手指,上滑開始~ 今天的內容是 【特征工程—結構化數據】 場景描述 特

elasticsearch結構查詢

{"query": {"bool": {"must": [{"term": {"aaa": "bbbbb"}},{"term": {"ip": "8.8.8.8"}}],"must_not": [],"should": []}},"from": 0,"size": 10,"sort": [],"aggs":

影像之結構特徵 廣度優先搜尋模板題

影像之結構化特徵 Problem Description 在影像比對中,有一種方法是利用影像中的邊緣(edge)資訊,計算每個邊緣資訊中具有代表性的結構化特徵,以作為比對兩張影像是否相似的判斷標準。Water-filling方法是從每個邊緣圖的一個端點開始,繞著相連的邊緣點走並依

Atitit 現代資訊檢索 Atitit 重要章節 息檢索建模 檢索評價 第8章 文字分類 Line 210: 第9章 索引和搜尋 第11章 Web檢索 第13章 結構文字檢索 目錄 L

Atitit 現代資訊檢索   Atitit 重要章節 息檢索建模 檢索評價  第8章 文字分類 Line 210: 第9章 索引和搜尋 第11章 Web檢索 第13章 結構化文字檢索   目錄   Line 1

dz論壇搜尋功能不能用的解決辦法之百度結構資料提交

dz論壇自帶的搜尋功能比百度站內搜尋或者360搜尋都好用,因為後者的搜尋只有收錄才能搜尋到,所以推薦大家使用dz自帶的搜尋。 但是我發現自己的論壇56微信平臺 自帶的搜尋功能不能用,輸入內容搜尋會跳出找不到頁面404,而且還自己變成了百度站內搜尋,經過我多方排查

2018最新實用BAT機器學習演算法崗位系列面試總結(結構資料特徵工程)

特徵工程,是對原始資料進行一系列工程處理,目的是去除原始資料中的雜質和冗餘,設計更高效的特徵來描述求解的問題與預測模型之間的關係。 特徵工程主要對以下兩種常用的資料型別做處理: (1)結構化資料。結構化資料型別可以看作關係型資料庫的一張表,每列都有清晰的定義,包

Scrapy系列教程(2)------Item(結構資料儲存結構

擴充套件Item 您可以通過繼承原始的Item來擴充套件item(新增更多的欄位或者修改某些欄位的元資料)。 例如: class DiscountedProduct(Product): discount_percent = scrapy.Field(serializer=str) di

Elasticsearch系列---初識搜尋

概要 本篇主要介紹搜尋的報文結構含義、搜尋超時時間的處理過程,提及了一下多索引搜尋和輕量搜尋,最後將精確搜尋與全文搜尋做了簡單的對比。 空搜尋 搜尋API最簡單的形式是不指定索引和型別的空搜尋,它將返回叢集下所有索引的所有文件(預設顯示10條): GET /_search 響應的結果示例(有篩選,只取了一條d

Elasticsearch系列---實戰搜尋語法

概要 本篇介紹Query DSL的語法案例,查詢語句的除錯,以及排序的相關內容。 基本語法 空查詢 最簡單的搜尋命令,不指定索引和型別的空搜尋,它將返回叢集下所有索引的所有文件(預設顯示10條): GET /_search {} 搜尋多個索引 GET /index1,index2/_doc/_search {

Elasticsearch系列---搜尋執行過程及scroll遊標查詢

概要 本篇主要介紹一下分散式環境中搜索的兩階段執行過程。 兩階段搜尋過程 回顧我們之前的CRUD操作,因為只對單個文件進行處理,文件的唯一性很容易確定,並且很容易知道是此文件在哪個node,哪個shard中。 但搜尋比CRUD複雜,符合搜尋條件的文件,可能散落在各個node、各個shard中,我們需要找到匹配

Elasticsearch系列---多欄位搜尋

### 概要 本篇介紹一下multi_match的best_fields、most_fields和cross_fields三種語法的場景和簡單示例。 ### 最佳欄位 bool查詢採取"more-matches-is-better"匹配越多分越高的方式,所以每條match語句的評分結果會被加在一起,從而