通過Elasticsearch使用的你的數據


Elasticsearch 系列導航

elasticsearch 與 elasticsearch-head 的安裝

ElasticSearch Index API && Mapping

在ElasticSearch中使用 IK 中文分詞插件

ElasticSearch 基本概念

Nest客戶端的基本使用方法

持續更新中

 

 正文

假設你已經有一份數據保存在Elasticsearch里,類似於下面這種schema,如果沒有參考導入測試數據

{
    "account_number": 0,
    "balance": 16623,
    "firstname": "Bradshaw",
    "lastname": "Mckenzie",
    "age": 29,
    "gender": "F",
    "address": "244 Columbus Place",
    "employer": "Euron",
    "email": "bradshawmckenzie@euron.com",
    "city": "Hobucken",
    "state": "CO"
}

 那么我們接下來就可以 過濾,搜索,聚合來獲取到我們想要的數據。

Elasticsearch提供了一套Json風格的領域特定語言來幫助查詢,被稱為Query DSL.

搜索通過在URL結尾加_search來指定,具體查詢提交通過Request Body來指定,

比如下面的Request Body:

query: 用來指定查詢條件

from:從第幾個開始取

size:取多少條記錄,默認10條,比如這個例子有13條記錄滿足條件,但是只返回1條記錄

sort:用來指定排序規則

OK,通過剛才的實驗,我們對查詢有了一個基本的認識,下面讓我們來繼續認識更加有趣的查詢:

  1. 減少返回字段的個數(默認情況下是返回一個文檔的所有字段信息)
    {
      "query": { "match_all": {} },
      "_source": ["account_number", "balance"]
    }
    
  2. 返回account_number等於20的account
    {
      "query": { "match": { "account_number": 20 } }
    }
    

     match是一個模糊匹配,但是由於account_number是long類型,所以這里當做精確匹配來過濾

  3. 返回address字段中包含mill的account
    {
      "query": { "match": { "address": "mill" } }
    }
    

     由於address是text類型,所以這里說的是包含mill而不是等於mill.

  4. 返回address字段中包含"mill" 或 "lane"的account
    {
      "query": { "match": { "address": "mill lane" } }
    }
    

     由於address是text類型,而且"mill lane"這里在查詢的時候被當作兩個詞來分別進行查詢

  5. 返回address字段中包含"mill lane"的account

     這里使用match_phrase(短語匹配)查詢類型,把"mill lane"當作一個整體來查詢

    {
      "query": { "match_phrase": { "address": "mill lane" } }
    }
    

     

  6. 返回address字段中同時包含"mill" 和 "lane"的account
    {
      "query": {
        "bool": {
          "must": [
            { "match": { "address": "mill" } },
            { "match": { "address": "lane" } }
          ]
        }
      }
    }
    

     這里使用了bool查詢語句,它允許我們組合多個小的查詢一起來完成稍微復雜的查詢,bool must 要求所有子查詢返回true,所有子查詢之間可以理解為一個and的操作。

  7. 返回address字段中包含"mill" 或 "lane"的account

     bool should 要求子查詢中的任一個滿足條件,可以理解為或的關系

    {
      "query": {
        "bool": {
          "should": [
            { "match": { "address": "mill" } },
            { "match": { "address": "lane" } }
          ]
        }
      }
    }
    

     

  8. 返回address字段中既不包含"mill" 也不包含 "lane"的account

     bool must_not子句之間是或的關系

    {
      "query": {
        "bool": {
          "must_not": [
            { "match": { "address": "mill" } },
            { "match": { "address": "lane" } }
          ]
        }
      }
    }
    

     

  9. 返回年齡等於40 且不住在ID地區的account
    {  "query": {
        "bool": {
          "must": [
            { "match": { "age": "40" } }
          ],
          "must_not": [
            { "match": { "state": "ID" } }
          ]
        }
      }
    }
    

        我們可以同時聯合must, should, and must_not子句在一個bool語句內,

         也可以繼續在bool子句下面繼續嵌套使用bool子句來完成更加復雜的查詢需求。

 Filter 過濾

        在返回的結果中有一個_score字段,score是一個數值,表示查詢條件和這個文檔的相關度,分數越高,說明某個文檔的相關度越高,

        反之,相關度越低,但是查詢 並不總是產生分數,尤其當你使用過濾子句來過濾文檔的時候,Elasticsearch會自動檢測這些場景,

       自動優化查詢,讓他不要去計算無用的分數,之前我們使用的bool查詢也支持filter子句,

        例如我們想獲取賬戶余額大於等於20000 小於等於30000的賬戶信息

{
  "query": {
    "bool": {
      "must": { "match_all": {} },
      "filter": {
        "range": {
          "balance": {
            "gte": 20000,
            "lte": 30000
          }
        }
      }
    }
  }
}

 上面的這個例子其實挺好理解的,所有在這個range范圍內的文檔都具有相等的匹配度,

  沒有哪一個文檔比其他的文檔匹配度更高,要么在這個范圍內,要么不在,所以相關度是相等的,

 就沒有必要再去計算這個score.

Aggregations聚合

聚合允許你給你的數據分組並獲取他們的統計信息,你可以把它和SQL里面的goup by 以及SQL的聚合函數聯系起來,

在Elasticsearch,你可以在一個響應里同時返回聚合信息和結果明細,

比如我們使用state來給所有的accounts分組,默認返回前10條聚合記錄,順序按照組內文檔數量的倒序排列

{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword"
      }
    }
  }
}

 你可以結合下面的SQL語句更好理解上面的語句

SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC
部分返回結果 如下顯示:
{
  "took": 29,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits" : {
    "total" : 1000,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "group_by_state" : {
      "doc_count_error_upper_bound": 20,
      "sum_other_doc_count": 770,
      "buckets" : [ {
        "key" : "ID",
        "doc_count" : 27
      }, {
        "key" : "TX",
        "doc_count" : 27
      }, {
        "key" : "AL",
        "doc_count" : 25
      }, {
        "key" : "MD",
        "doc_count" : 25
      }, {
        "key" : "TN",
        "doc_count" : 23
      }, {
        "key" : "MA",
        "doc_count" : 21
      }, {
        "key" : "NC",
        "doc_count" : 21
      }, {
        "key" : "ND",
        "doc_count" : 21
      }, {
        "key" : "ME",
        "doc_count" : 20
      }, {
        "key" : "MO",
        "doc_count" : 20
      } ]
    }
  }
}

 你可以觀察到,上面的聚合我們設置size=0,不去顯示符合條件的原始記錄,

因為我們這次僅僅需要聚合的結果信息,如果你也需要原始記錄信息,那么你可以重新指定size的大小

下面這個例子我們來求余額的平均值

{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword"
      },
      "aggs": {
        "average_balance": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}

 返回如下的結果,可以看到這里我們在group_by_state里面嵌套使用了average_balance,這是一種比較通用的做法,

你可以在任意聚合內嵌套任意聚合來獲取需要的統計信息。

下面這個例子演示根據年齡組來分組,然后根據性別來分組最后求賬戶余額的平均值

{
  "size": 0,
  "aggs": {
    "group_by_age": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "from": 20,
            "to": 30
          },
          {
            "from": 30,
            "to": 40
          },
          {
            "from": 40,
            "to": 50
          }
        ]
      },
      "aggs": {
        "group_by_gender": {
          "terms": {
            "field": "gender.keyword"
          },
          "aggs": {
            "average_balance": {
              "avg": {
                "field": "balance"
              }
            }
          }
        }
      }
    }
  }
}

 下面是年齡組分組 計算聚合的部分返回結果:

 

 

下面

 

 
       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM