Python連線es筆記二之查詢方式彙總

Hunter發表於2023-04-18
本文首發於公眾號:Hunter後端
原文連結:Python連線es筆記二之查詢方式彙總

上一節除了介紹使用 Python 連線 es,還有最簡單的 query() 方法,這一節介紹一下幾種其他的查詢方式。

以下是本篇筆記目錄:

  1. query() 方法介紹
  2. Q() 查詢
  3. 排序
  4. 分頁
  5. source() 指定返回欄位
  6. extra() 操作
  7. count() 總數
  8. from_dict() 函式

1、query() 方法介紹

在上一節中介紹了 query() 的一個簡單示例,如下:

s = Search(using="default").index("exam")

s = s.query("match", name="張三丰")

query() 中接受兩個引數,第一個是欄位查詢的方式,比如這裡是 match,也可以是 term,這個依照查詢的目的來替換。

第二個則是查詢的欄位與值,比如這裡是查詢的 name 欄位為 "張三丰" 的資料。

如果是有多個條件,比如 name="張三丰",address="中國" 的資料,這裡的 = ,並非是完全等於的意思,而是會依照前面的查詢方式,比如 match 或 term 進行類似的分詞或者模糊搜尋。

如果是上面多個條件的查詢,可以直接在後面加上類似的 query():

s = s.query("match", name="張三丰").query("match", address="中國")

這兩個 query() 透過鏈式操作連在一起轉換成 es 語句就是使用 must 將多條件連線在一起,我們可以使用 to_dict() 方式來檢視:

s.to_dict()

# {'query': {'bool': {'must': [{'match': {'name': '張三丰'}}, {'match': {'address': '中國'}}]}}}

2、Q() 查詢

如果看過之前我寫過的 Django 系列筆記,應該記得在 Django 裡也有個 Q() 方法的查詢,和這裡的一樣,也是用於條件的聯合,與或非條件都可以實現。

引入方式如下:

from elasticsearch_dsl import Q

但是如果是在 Django 中使用 es 的連線,也是同樣使用 Q() 方法,我們可以使用 as 來區分,這裡我們對於 es 的 Q() 方法可以使用 ES_Q() 來區分:

from elasticsearch_dsl import Q as ES_Q

單個條件的使用 Q() 如下:

s = s.query(ES_Q("match", name="張三丰"))

如下使用 dict 形式的操作也是等效的:

s = s.query(ES_Q({"match": {"name": "張三丰"}}))

與操作

對於這兩個條件,如果想要實現它們的與操作:

q1 = ES_Q("match", name="張三丰")
q2 = ES_Q("match", address="中國")

可以如下實現:

s = s.query(q1 & q2)

或操作

如果是想實現上面的或操作,可以如下:

s = s.query(q1 | q2)

非操作

如果是想取反,直接在條件前加一個 ~ 即可:

q1 = ~ES_Q("match", name="張三丰")
s = s.query(q1)

multi_match

如果是搜尋多欄位,可以如下操作:

q = ES_Q("multi_match", query="中國 張三丰", fields=["name", "address"])

s = s.query(q)

text.keyword 操作

對於 es 中 text 欄位,前面我們介紹過 .keyword 的查詢方式,是將 text 欄位作為一個整體進行查詢,在 ES_Q() 中,以下兩種操作是等效的:

q = ES_Q({"term": {"address.keyword": "中國湖北省"}})

q = ES_Q("term", address__keyword="中國湖北省")

filter() 操作

在 es 中的 filter 操作,在 Python 中是一個 filter() 函式,可以直接使用:

q = ES_Q("term", name="張三丰")
s = s.filter(q)

range 操作

實現大小於的操作示例如下:

q = ES_Q({"range": {"age": {"gte": 21}}})
s = s.query(q)

exclude() 操作

如果是想取反,除了使用 ~Q(),還可以直接使用 exclude() 函式,這個和 Django 裡的操作也是一樣的:

q = ES_Q("term", name="張三丰")
s = s.exclude(q)

3、排序

如果是想對返回的結果進行排序操作,直接使用 .sort() 方法。

比如想對 age 欄位排序,正序返回資料,可如下操作:

s = s.sort("age")

如果是想倒序返回,可以如下操作:

s = s.sort("-age")

多欄位排序直接在後面跟上就行:

s = s.sort("-age", "name")

4、分頁

Python 連線 es 進行分頁,可以直接使用 Python 裡的切片操作,比如:

s = s[5:10]

5、source() 指定返回欄位

我們可以透過 source() 方法指定返回的欄位:

s = s.source(["name", "address"])

source() 方法還可以接受 includes 和 excludes 引數來指定返回的欄位或者不返回的欄位,這個和 es 的原生處理方式是一致的:

s = s.source(
    includes=["address"],
    excludes=["name"]
)

6、extra() 操作

extra() 函式接受一些查詢的額外屬性,比如 size 引數決定返回條數,比如 from 引數可以決定從第幾條資料開始返回,sort 引數決定排序方式,以及 _source 引數決定返回的欄位。

比如我們想要返回的資料從第 2 條資料開始,返回兩條,按照 name 欄位進行排序,只返回 name 和 _id 欄位,可以如下操作:

s = Search(using="default").index("exam")
s = s.extra(
    sort="name",
    _source=["name"],
    **{
        "from": 1,
        "size": 2
    }
)
response = s.execute()

7、count() 總數

前面介紹過獲取符合條件的總數,可以透過 response.hits.total.value 的方式獲得,其實對於 Search(),可以直接使用 count() 函式:

count = s.count()

8、from_dict() 函式

如果我們想直接執行 kibana 裡執行的命令,可以使用 from_dict() 函式,比如:

s = s.from_dict(
  {
    "query": {
      "term": {
        "name": {
          "value": "張三丰"
        }
      }
    }
  }
)

如果想獲取更多後端相關文章,可掃碼關注閱讀:

image.png

相關文章