Elasticsearch第15節(jié) 分頁、copy_to、sort、score、doc_value

一、 多索引查詢

GET /lib1/_search
GET /lib*/_search
GET /lib1,lib2/_search
GET /lib1,lib2/_search
GET /_all/_search
GET _search

二、 分頁查詢中的deep paging(深度分頁)問題

GET /myindex/_search
{
  "from":0,
  "size":3,
  "version":true,   
  "query":{
    "match":{
      "intrest":"basketball running"
    } 
  }
}
GET /_search?from=0&size=3

deep paging : 查詢的很深,比如一個索引有三個primary shard,分別存儲了6000條數(shù)據(jù),我們要得到笫100頁的數(shù)據(jù)(每頁10條),類似這種情況就叫deep paging

1. 如何得到笫100頁的10條數(shù)據(jù)?

1.1 深度分頁的錯誤做法

在每個shard中搜索990到999這10條數(shù)據(jù),然后用這30條數(shù)據(jù)排序,排序之后取10條數(shù)據(jù)就是要搜索的數(shù)據(jù),這種做法是?的,因為3個shard中的數(shù)據(jù)的
_score分數(shù)不一祥,可能某一個shard中第一條數(shù)據(jù)的_score分數(shù)比另一個shard中笫1000條都要高,所以在每個shard中搜索990到999這10條數(shù)據(jù)然后排 序的倣法是不正確的。

1.2 深度分頁的正確做法

是每個shard把0到999條數(shù)據(jù)全部搜索出來(按排序順序),然后全部返回給coordinate node?甶coordinate按_score分數(shù)排序后,出第 100頁的10條數(shù)據(jù),然后返回紿客戶端,

1.3 deep paging性能問題
  1. 耗費網(wǎng)絡(luò)芾寬,因為搜索過深的話,各shard要把數(shù)據(jù)傳送紿coordinate node,這個過程是有大量數(shù)據(jù)傳遞的,消耗網(wǎng)絡(luò)。
  2. 消耗內(nèi)存,各shard要把數(shù)據(jù)恃送給coordinate node,這個傳遞回來的數(shù)振,是被coordinate nodW存在內(nèi)存中的,這樣今大量消耗內(nèi)存.
  3. 消耗cpu coordinate node要把傳回來的數(shù)據(jù)逬行排序,這個排序過程很消耗cpu.
    鑒于deep paging的性能間題,所以應(yīng)盡量減少使用


三、query String 查詢以及copy_to


get /lib1/_search?q=name:xiaochao
get /lib1/_search?q=+name:xiaochao
get /lib1/_search?q=-name:xiaochao
copy_to字段是把其它字段中的值,以空格為分隔符組成一個大字符串,然后被分析和索引,但是不存儲,不能顯示,只能用來做查詢參數(shù)。字段類型必須為text

//
DELETE /testindex
#copy_to mapping 提高搜索效率
PUT /testindex
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 0
  },
  "mappings": {
    "properties": {
      "age" : {"type" : "long"},
      "birthday" : {"type" : "date"},
      "name" : {"type" : "text","copy_to": "fullContent"},#自定義copy_to字段名
      "content":{"type":"text","copy_to": "fullContent"},#自定義copy_to字段名
      "price":{"type": "double"},
      "number":{"type": "integer"}
    }
  }
}
#數(shù)據(jù)1
PUT /testindex/_doc/xiaochao
{
  "name":"xiaochao",
  "age":22,
  "birthday":"1991-02-23",
  "content":"good boy",
  "price":100,
  "number":1
}
#數(shù)據(jù)2
PUT /testindex/_doc/xiaoyi
{
  "name":"xiaoyi",
  "age":22,
  "birthday":"1992-02-23",
  "content":"good girl",
  "price":100,
  "number":1
}
#數(shù)據(jù)3
PUT /testindex/_doc/xiaofei
{
  "name":"xiaofei",
  "age":22,
  "birthday":"1997-02-23",
  "content":"little girl",
  "price":100,
  "number":1
}
#通過copy_to字段索引,避免全字段檢索
GET /testindex/_search?q=fullContent:xiaofei


四、字符型排序


ES對字符串分詞了,所以對字符串類型排序不準確,會報錯。解決辦法:
對字段索引2次,一次索引分詞,用于搜索;一次索引不分詞,用于排序。

DELETE test1
//
PUT /test1
{
  "mappings": {
    "properties": {
      "age" : {"type" : "long"},
      "birthday" : {"type" : "date","index": false},
      "name" : {
          "type" : "text",
          "fields" : {
            "raw" : {
              "type" : "keyword"    #fields.raw.type=keyword是必須的
            }
          },
          "fielddata":true      #這個必須的
        }
    }
  }
}
#文檔1
PUT /test1/_doc/1
{
  "age":10,
  "birthday":"2019-09-23",
  "name":"xiaochao"
}
#文檔2
PUT /test1/_doc/2
{
  "age":20,
  "birthday":"2019-02-23",
  "name":"xiaoyi"
}
#文檔3
PUT /test1/_doc/3
{
  "age":30,
  "birthday":"2019-07-23",
  "name":"xiaofei"
}
#text查詢排序
GET /test1/_search
{
  "query":{
    "match_all": {}
  },
  "sort": [
    {
      "name.raw": {    #.raw是根據(jù)整個文本排序,而不是被分的詞
        "order": "asc"
      }
    }
  ]
}


五、如何計算相關(guān)度分數(shù)


使用的是TF/IDF算法(Term Frequency&lnverse Document Frequency)

  1. Term Frequency(詞條頻率) 我們查詢的文本中的詞條在 document本 中出現(xiàn)了多少次,出現(xiàn)次數(shù)越多,相關(guān)度越高
    搜索內(nèi)容:hello world
#
Hello, I love china.
Hello world,how are you!

2.lnverse Document Frequency(倒排索引頻率): 我們查詢的文本中的詞條在 索引的所有文檔中 出現(xiàn)了多少次,出現(xiàn)的次數(shù)越多,相關(guān)度越低
搜索內(nèi)容:hello world

//hello在索引的  所有文檔中   出現(xiàn)了500次,world出現(xiàn)了 100次 
//所有
hello, what are you doing?
I like the world.
  1. Field-length(字段長度歸約)norm : field越長相關(guān)度越低
    搜索內(nèi)容:hello world
//hello 所在文本短,得分高
{'title':"hello,what's your name?',',content':{'owieurowieuolsdjflk'}}
#world所在文本長,得分低
{'title':'hi,good morning','contenf:{'lkjkljkj................world'}}

查看分數(shù)是如何計算的:

GET /myindex/_search?explain=true
GET /myindex/_doc/_explain
{
    "query":{
    "match":{
      "intrest":"qwer"
    } 
  }
}

#沒有article10的文檔
GET /myindex/_doc/article10/_explain
{
    "query":{
    "match":{
      "intrest":"basketball running"
    } 
  }
}
--------------------------------
# Deprecation: [types removal] Specifying a type in explain requests is deprecated.
{
  "_index" : "myindex",
  "_type" : "_doc",
  "_id" : "article10",
  "matched" : false
}


六、 Doc Values 解析 (正排索引)

DocValues其實是Lucene在構(gòu)建倒排索引時,會額外建立一個有序的正排索引(基于 document => field value的映射列表)
{'birthday':'1985-11-11','age':23}
{birthday':'1989-11-17','age':29}

document age birthday
doc1 23 1985-11-11
doc2 29 1989-11-17

存儲在磁盤上,節(jié)省內(nèi)存
對排序、分組和一些聚合操作能夠大大提升性能
注意:默認對不分詞的字段是開啟的,對分詞字段無效(需要把fielddata置為true)

doc_values:false 關(guān)閉正排索引

//
DELETE test1
#創(chuàng)建mapping
PUT /test1
{
  "mappings": {
    "properties": {
      "age" : {"type" : "long","doc_values":false}, #doc_values 關(guān)閉正排索引
      "birthday" : {"type" : "date","index": false},
      "name" : {"type" : "text"}
    }
  }
}
#數(shù)據(jù)1
PUT /test1/_doc/1
{
  "age":10,
  "birthday":"2019-09-23",
  "name":"xiaochao"
}
#數(shù)據(jù)2
PUT /test1/_doc/2
{
  "age":20,
  "birthday":"2019-02-23",
  "name":"xiaoyi"
}
#數(shù)據(jù)3
PUT /test1/_doc/3
{
  "age":30,
  "birthday":"2019-07-23",
  "name":"xiaofei"
}
#查詢結(jié)果報錯
GET /test1/_search
{
  "query":{
    "match_all": {}
  },
  "sort": [
    {
      "age": {
        "order": "asc"
      }
    }
  ]
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容