Elasticsearch學習系列三(搜尋案例實戰)

2022-06-22 12:01:37

Query DSL

Es提供了基於JSON的完整查詢DSL(Domain Specific Language 特定域的語言)來定義查詢。將查詢DSL視為查詢的AST(抽象語法樹)。它由兩種子句組成:

  • 葉子查詢子句

葉子查詢子句,在特定域中尋找特定的值,如match、term或range查詢

  • 複合查詢子句

複合查詢子句包裝其他葉子查詢或複合查詢,並用於以邏輯方式組合多個查詢。如bool、dis_max、constant_score查詢

1. 查詢所有

POST /索引名稱/_search
{
  "query":{
    "match_all": {}
  }
}

查詢結果範例:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "test-demo1",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "name" : "百度3",
          "job" : "運營",
          "amt" : "3000.34",
          "logo" : "http://www.lgstatic.com/ttasdf2",
          "createTime" : "20220303230000"
        }
      }
      ...省略2條資料
    ]
  }
}

  • took:查詢花費時間,單位是毫秒
  • time_out:是否超時
  • _shards:分片資訊
  • hits:搜尋結果總覽物件
    • total:搜尋到的總條數
    • max_score:所有結果中檔案得分的最高分
    • hits:搜尋結果的檔案物件陣列,每個元素是一條搜尋到的檔案資訊
      • _index:索引庫
      • _type:檔案型別
      • _id:檔案id
      • _score:檔案得分
      • _source:檔案的源資料

2. 全文搜尋

全文搜尋能夠搜尋已分析的文字欄位,如電子郵件正文、商品描述等。

先造一些測試資料:

PUT /item
{
  "settings": {},
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "images": {
        "type": "keyword"
      },
      "price": {
        "type": "float"
      }
    }
  }
}

POST /item/_doc/
{
"title": "小米電視4A",
"images": "https://s3.ap-northeast-1.wasabisys.com/img.tw511.com/202206/12479122ahwuydsoin1.jpg",
"price": 4288
}

POST /item/_doc/
{
"title": "小米手機",
"images": "https://s3.ap-northeast-1.wasabisys.com/img.tw511.com/202206/12479122ahwuydsoin1.jpg",
"price": 2688
}

POST /item/_doc/
{
"title": "蘋果手機",
"images": "https://s3.ap-northeast-1.wasabisys.com/img.tw511.com/202206/12479122ahwuydsoin1.jpg",
"price": 5699
}
2.1 匹配搜尋
  • or關係

match型別的查詢,會把查詢條件分詞,多個詞條之間是or的關係。如下面的例子,會根據小米和手機分別去搜尋,能搜出3條資料。

POST /item/_search
{
  "query":{
    "match": {
      "title": "小米手機"
    }
  }
}
  • and關係
POST /item/_search
{
  "query":{
    "match": {
      "title": {
        "query": "小米手機",
        "operator":"and"
      }
    }
  }
}
2.2 短語搜尋

match_phrase查詢用來對一個欄位進行短語查詢,可以指定analyzer、slop移動因子

POST /item/_search
{
  "query":{
   "match_phrase": {
     "title": "小米手機"
   }
  }
}

帶slop:

POST /item/_search
{
  "query":{
   "match_phrase": {
     "title": {
       "query": "手機小米",
       "slop":2
     }
   }
  }
}

slop引數告訴match_phrase查詢詞條能夠相隔多遠時仍然將檔案視為匹配。相隔多遠的意思是,你需要移動一個詞條多少次來讓查詢和檔案匹配

2.3 query_string 查詢

query string提供了無需指定某欄位而對檔案全文進行匹配查詢的一個高階查詢,同時可以指定在哪些欄位上進行匹配。

GET /item/_search
{
  "query": {
    "query_string": {
      "query": "2688"
    }
  }
}

GET /item/_search
{
  "query": {
    "query_string": {
      "default_field": "price", 
      "query": "2688"
    }
  }
}

GET /item/_search
{
  "query": {
    "query_string": {
      "default_field": "title", 
      "query": "手機 OR 小米"
    }
  }
}

GET /item/_search
{
  "query": {
    "query_string": {
      "default_field": "title", 
      "query": "手機 and 小米"
    }
  }
}

#模糊查詢
GET /item/_search
{
  "query": {
    "query_string": {
      "default_field": "title", 
      "query": "小米~1"
    }
  }
}

#多欄位支援
GET /item/_search
{
  "query": {
    "query_string": {
      "fields": ["title","price"], 
      "query": "2699"
    }
  }
}
2.4 多欄位匹配搜尋

如果你需要在多個欄位上進行文字搜尋,可用multi_match。

GET /item/_search
{
  "query": {
    "multi_match": {
      "query": "2688",
      "fields": ["title","price"]
    }
  }
}

#還可以使用*設定

GET /item/_search
{
  "query": {
    "multi_match": {
      "query": "2688",
      "fields": ["title","pri*"]
    }
  }
}

3. 詞條搜尋

可以使用term-level queries根據結構化資料中的精確值查詢檔案。term-level queries不分析搜尋詞。搜尋詞與儲存在欄位中的詞需要完全匹配

3.1 詞條普通搜尋

用於查詢指定欄位包含某個搜尋詞的檔案

POST /item/_search
{
  "query": {
    "term": {
      "title":"小米"
    }
  }
}
3.2 詞條集合搜尋
POST /item/_search
{
  "query": {
    "terms": {
      "title": ["小米","電視"]
    }
  }
}
3.3 範圍搜尋
  • gte:大於等於
  • gt:大於
  • lte:小於等於
  • lt:小於
  • boost:查詢權重
POST /item/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 10,
        "lte": 3000
      }
    }
  }
}

#日期範圍
POST /item/_search
{
  "query": {
    "range": {
      "createTime": {
        "gte": "2022-01-01",
        "lte": "2022-02-01",
        "format": "yyyy-MM-dd"
      }
    }
  }
}
3.4 不為空搜尋
GET /item/_search
{
  "query": {
    "exists": {
      "field": "price"
    }
  }
}
3.5 詞項字首搜尋
GET /item/_search
{
  "query": {
    "prefix": {
      "title": {
        "value": "小米"
      }
    }
  }
}
3.6 萬用字元搜尋
GET /item/_search
{
  "query": {
    "wildcard": {
      "title":"小*"
    }
  }
}
3.7 正則搜尋
GET /item/_search
{
  "query": {
    "regexp": {
      "title":"小米[a-z0-9]"
    }
  }
}
3.8 模糊搜尋
GET /item/_search
{
  "query": {
    "fuzzy": {
      "title": "手機"
    }
  }
}

#錯別字糾正
GET /item/_search
{
  "query": {
    "fuzzy": {
      "title": {
        "value": "大米",
        "fuzziness": 1
      }
    }
  }
}
3.9 ids搜尋
GET /item/_search
{
  "query": {
    "ids": {
      "values": ["t76YgYEB9TD2fYkcLzha","tb6XgYEB9TD2fYkc6zhx"]
    }
  }
}

4. 複合搜尋

4.1 constant_score,用來包裝另一個查詢,將查詢匹配的檔案的評分設為一個常值
GET /item/_search
{
  "query": {
   "constant_score": {
     "filter": {
       "term": {
         "title": "小米"
       }
     },
     "boost": 1.2
   }
  }
}
4.2 bool query,用bool組合多個查詢子句為一個查詢。
  • must:必須滿足
  • filter:必須滿足,但執行的是filter上下文,不參與、影響評分
  • should:或
  • must_not:必須不滿足,在filter上下文中執行,不參與、不影響評分
POST /item/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "title": "小米"
          }
        }
      ], "filter": {
        "term": {
          "title": "電視"
        }
      },"must_not": [
        {
          "range": {
            "price": {
              "gte": 4200,
              "lte": 4300
            }
          }
        }
      ]
      ,"minimum_should_match": 0
    }
  }
}

minimum_should_match代表了最小匹配精度,如果設定為1,代表should語句中至少需要有一個條件滿足。

5. 排序

5.1 相關性評分排序

預設情況下,返回的結果是按照相關性進行排序的。預設排序是_score降序

# 按照評分升序
GET /item/_search
{
  "query": {
    "match_all": {}
  },
  "sort":[{
    "_score":{
      "order":"asc"
    }
  }
  ]
}


#根據欄位值排序
GET /item/_search
{
  "query": {
    "match_all": {}
  },
  "sort":[{
    "price":{
      "order":"asc"
    }
  }
  ]
}

#多個欄位的排序
GET /item/_search
{
  "query": {
    "match_all": {}
  },
  "sort":[{
    "price":{
      "order":"asc"
    }
  },{
    "createTime": {
      "order":"desc"
    }
  }
  ]
}

6.分頁

size:每頁顯示多少條

from:當前頁起始索引

POST /item/_search
{
  "query": {
    "match_all": {}
  }
  ,"size": 2,
  "from": 0
}

7. 高亮

POST /item/_search
{
  "query": {
    "match": {
      "title": "小米"
    }
  },
  "highlight": {
    "pre_tags": "<font color='pink'>",
    "post_tags": "</font>",
    "fields": [{"title":{}}]
  }
}
  • pre_tags:前置標籤
  • post_tags:後置標籤
  • fields:需要高亮的欄位
    • title:這裡宣告title欄位需要高亮

8. 檔案批次操作

8.1 mget批次查詢

不同的索引

GET /_mget
{
  "docs":[
    {
      "_index":"item",
      "_id":"tb6XgYEB9TD2fYkc6zhx"
    },
    {
      "_index":"test-location",
      "_id":1
    }
    ]
}

相同的索引

POST /test-location/_search
{
  "query": {
    "ids": {
      "values": ["1","2"]
    }
  }
}
8.2 bulk批次增刪改

語法:

POST /_bulk
{"action": {"metadata"}}
{"data"}

範例:

POST /_bulk
  {"delete":{"_index":"item","_id":"tb6XgYEB9TD2fYkc6zhx"}}
  {"create":{"_index":"item","_id":"1"}}
  {"title":"華為電腦","price":2333}
  {"update":{"_index":"item","_id":2}}
  {"doc":{"title":"冰箱"}}
  • delete:刪除一個檔案,刪除沒有請求體,只需要一個json串就行
  • create:相當於強制建立
  • index:普通的PUT操作,可以建立也可以全量替換
  • update:執行的是區域性更新

格式:每個json不能換行,相鄰json必須換行

隔離:每個操作互不影響,操作失敗的行會返回其失敗資訊

實際用法:bulk請求一次不要太大,否則一下積壓到記憶體中,效能會下降。所以,一次請求幾千個操作、大小在幾M正好。bulk會將要處理的資料載入記憶體中,所以資料量是有限的,最佳的資料量不是一個確定的資料,它取決於你的硬體,你的檔案大小以及複雜性,你的索引以及搜尋的負載。一般建議是1000-5000個檔案,大小建議是5-15MB,預設不能超過100M,可以在es的組態檔(ES的config下的elasticsearch.yml)中設定。

http.max_content_length: 10mb