ElasticSearch 復(fù)雜查詢

測試數(shù)據(jù)

首先下載 elastic 官方的測試數(shù)據(jù):下載地址
通過 curl 上傳測試數(shù)據(jù)

curl -H "Content-Type: application/json" -XPOST "localhost:9200/bank/_doc/_bulk?pretty&refresh" --data-binary "@accounts.json"
curl "localhost:9200/_cat/indices?v"

也可以使用 postman 上傳 localhost:9200/bank/_doc/_bulk?pretty&refresh

image.png

不管使用什么方式上傳,如果上傳成功,返回的 response 都應(yīng)該是這樣的:

{
    "took": 1016,
    "errors": false,
    "items": [
        {
            "index": {
                "_index": "bank",
                "_type": "_doc",
                "_id": "1",
                "_version": 1,
                "result": "created",
                "forced_refresh": true,
                "_shards": {
                    "total": 2,
                    "successful": 1,
                    "failed": 0
                },
                "_seq_no": 0,
                "_primary_term": 1,
                "status": 201
            }
        }
        ......
    ]
}

查詢

elastic 可以通過兩種方式查詢,一種是通過 URL 傳參方式,另種是通過 Body 傳 JSON 格式字符串的方式查詢。

URL 傳參方式查詢

首先我們來看一下 URL 傳參的方式

GET /bank/_search?q=*&sort=account_number:asc&pretty

Response

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1000,
    "max_score" : null,
    "hits" : [
      {
        "_index" : "bank",
        "_type" : "_doc",
        "_id" : "0",
        "_score" : null,
        "_source" : {
          "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"
        },
        "sort" : [
          0
        ]
      }, ...
    ]
}

仔細(xì)看一下就會能夠發(fā)現(xiàn),返回的的數(shù)據(jù)是以 account_number 升序排列的。

解釋一下上面查詢語句的作用,/bank/_search 查詢 bank 索引, q=* 表示所有文檔,sort=account_number 表示以 account_number 字段作為排序依據(jù),asc 表示升序排列,&pretty 是用來返回可讀性好的數(shù)據(jù)。

Body 傳 JSON 字符方式查詢

向下面這種 JSON 風(fēng)格的查詢語句,elastic 稱為 DSL 語句,它效果跟上面作用是一樣的,很明顯 DSL 可讀性比明顯好于上面的,下面將重點(diǎn)介紹 DSL 語句。

GET /bank/_search
{
  "query": {
    "match_all": {
      
    }
  }
  , "sort": [
    {
      "account_number": {
        "order": "asc" # desc 降序
      }
    }
  ]
}

DSL 查詢語句

首先來看個最簡單的例子,查詢 bank 索引中的所有文檔

GET /bank/_search
{
  "query": { "match_all": {} }
}

size 指定返回文檔數(shù)量,默認(rèn)值是10(之前只有十條記錄就是這個原因),配合 form 可以達(dá)到跟 MySQLlimit 的類似的效果。

GET /bank/_search
{
  "query": { "match_all": {} }
  , "size": 2
}

查詢 10 ~ 19 的記錄 [10,20),from 的默認(rèn)值是 0

GET /bank/_search
{
  "query": { "match_all": {} },
  "from": 10,
  "size": 10
}

通過上面我們已經(jīng)學(xué)會了 排序,跟獲取指定區(qū)間文檔了,現(xiàn)在來繼續(xù)學(xué)習(xí),通過看上面的返回值可以知道我們默認(rèn)返回的是整個文檔,我們能不能向 MySQL 那樣只查詢特定字段呢,答案是可以的,看下面示例。

只查詢文檔中的 account_numberbalance 字段

GET /bank/_search
{
  "query": { "match_all": {} },
  "_source": ["account_number", "balance"]
}

Response (只截取了部分記錄)

{
  "_index" : "bank",
  "_type" : "_doc",
  "_id" : "25",
  "_score" : 1.0,
  "_source" : {
    "account_number" : 25,
    "balance" : 40540
  }
},
{
  "_index" : "bank",
  "_type" : "_doc",
  "_id" : "44",
  "_score" : 1.0,
  "_source" : {
    "account_number" : 44,
    "balance" : 34487
  }
}

精確查詢(對于字段類型為 數(shù)值的記錄),獲取 age = 37 的文檔

GET /bank/_search
{
  "query": { "match": { "age": 37}}
}

模糊查詢(對于句子),查找 adress 中包含 mill 的文檔(不區(qū)分大小寫)

GET /bank/_search
{
  "query": { "match": { "address": "mill" } }
}

查找 adress 中包含 milllane 的文檔(不區(qū)分大小寫)

GET /bank/_search
{
  "query": { "match": { "address": "mill lane" } }
}

返回文檔中元數(shù)據(jù)中的 hits.hits._sroce 表示匹配得分,1 表示完全匹配,分?jǐn)?shù)越高排的越靠前。另外還需要注意的是 match 只能指定一個字段。這些規(guī)則對于下面的也適用。

bool qurey

must 需要同時匹配,and 關(guān)系,這個返回 adress 中包含 milllane 的文檔

GET /bank/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}

should 匹配其中一個就可以了,or 關(guān)系,這個返回 adress 中包含 mill
lane的文檔

GET /bank/_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}

must_not 不匹配其中任何一個,是 nor(或非)的的關(guān)系,這個返回adress不包含 mill
lane的文檔

GET /bank/_search
{
  "query": {
    "bool": {
      "must_not": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}

他們還可以組合使用,讓我們看下面這個例子,查詢 age = 24, state != ID 的顧客。

GET /bank/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "age": "24" } }
      ],
      "must_not": [
        { "match": { "state": "ID" } }
      ]
    }
  }
  , "size": 1
}

Response

  "hits" : {
    "total" : 42,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "bank",
        "_type" : "_doc",
        "_id" : "335",
        "_score" : 1.0,
        "_source" : {
          "account_number" : 335,
          "balance" : 35433,
          "firstname" : "Vera",
          "lastname" : "Hansen",
          "age" : 24,
          "gender" : "M",
          "address" : "252 Bushwick Avenue",
          "employer" : "Zanilla",
          "email" : "verahansen@zanilla.com",
          "city" : "Manila",
          "state" : "TN"
        }
      }
    ]
  }

Filter 過濾條件

常用的條件操作符有:

  • (>) 大于 - gt
  • (<)小于 - lt
  • (>=)大于等于 - gte
  • (<= ) 小于等于 - lte

查詢 age <= 20的用戶

GET /bank/_search
{
  "query": {
    "bool": {
      "must": { "match_all": {} },
      "filter": {
        "range": {
          "age": {
            "lte": 20
          }
        }
      }
    }
  }
}

還可以組合使用,下面的查詢 2000 <= balance <= 3000 的用戶

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

聚合

看寫下面這個例子,統(tǒng)計男女人數(shù)(默認(rèn)是取前10,按統(tǒng)計數(shù)量降序排列),查詢效果相當(dāng)于 SQL:SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC LIMIT 10;

GET /bank/_search
{a
  "size": 0,
  "aggs": {
    "group_by_gender": {
      "terms": {
        "field": "gender.keyword"
      }
    }
  }
}

上面的size = 0 表示只看聚合結(jié)果,如果要聚合的字段是數(shù)值類型,直接使用字段名,后面不用加 .keyword,例如統(tǒng)計年齡人數(shù) "field": "age"

Response:

  "hits" : {
    "total" : 1000,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "group_by_gender" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "M",
          "doc_count" : 507
        },
        {
          "key" : "F",
          "doc_count" : 493
        }
      ]
    }
  }

設(shè)置數(shù)量

"terms": {
        "field": "age"
        , "size": 100
      }

接下來我們來個稍微復(fù)雜一點(diǎn)的查詢,查詢 哪個年齡的用戶平均存款最多

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "group_by_age": {  # 可以自定義名字
      "terms": {
        "field": "age",
        "order": {
          "average_balance": "desc" # 依據(jù) average_balance 降序排列
        }
        , "size": 1 # 顯示最前面的 1 個
      },
      "aggs": {
        "average_balance": {  # 可以自定義名字
          "avg": {
            "field": "balance" # 分組后 balance 的平均值
          }
        }
      }
    }
  }
}

Response:

"aggregations" : {
    "group_by_age" : {
      "doc_count_error_upper_bound" : -1,
      "sum_other_doc_count" : 976,
      "buckets" : [
        {
          "key" : 29,
          "doc_count" : 24,
          "average_balance" : {
            "value" : 33540.666666666664
          }
        }
      ]
    }
  }

關(guān)于查詢就先寫到這里,上面的都是看官方記錄的筆記,想了解更多內(nèi)容可以看官方文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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