Query DSL trong elasticsearch

Elasticsearch cung cấp một bộ Query DSL (Domain Specific Language) dựa trên JSON để định nghĩa các truy vấn. Có thể cọi Query DSL là một AST(Abstract Syntax Tree) của các truy vấn, bao gồm hai loại mệnh đề:

  • Leaf query clauses: Những mệnh đề này tìm những giá trị cụ thể của những trường cụ thể. Ví dụ như các truy vấn match, termrange.
  • Compound query clauses: Những mệnh đề này kết hợp các leaf query và các compound query khác để thu được kết quả mong muốn.

Các mệnh đề truy vấn hoạt động theo cách khác nhau tùy thuộc vào nó được sử dụng trong query context hay filter context.

Vậy query contextfilter context là gì?

Query context và Filter context

Query context

Một mệnh đề truy vấn được sử dụng trong query context trả lời câu hỏi "document này phù hợp với mệnh đề truy vấn nhiều như thế nào?". Bên cạnh việc xác định xem document có phù hợp với truy vấn hay không thì mệnh đề truy vấn tính thêm _score (giá trị của _score thể hiện mức độ phù hợp của document).

Query context có hiệu lực khi mệnh đề truy vấn được truyền vào tham số query trong search API.

Filter context

Trong filter context, một mệnh đề truy vấn trả lời câu hỏi "document này có phù hợp với mệnh đề truy vấn không?". Câu trả lời đơn giản chỉ là có hoặc không, và score không được tính.

Filter context có hiệu lực khi truyền mệnh đề truy vấn vào tham số filter hay must_not.

Create sample index

Trước khi đi vào tìm hiểu các query thì ta sẽ tạo một sample index để thực hành các ví dụ. Tạo index:

PUT schools

Thêm data:

POST schools/_doc/10
{
   "first_name":"Saint Paul", "last_name":"School", "description":"ICSE Afiliation",
   "street":"Dawarka", "city":"Delhi", "state":"Delhi", "zip":"110075",
   "location":[28.5733056, 77.0122136], "fees":5000,
   "tags":["Good Faculty", "Great Sports"], "rating":"4.5"
}
POST schools/_doc/16
{
   "first_name":"Crescent", "last_name": "School", "description":"State Board Affiliation",
   "street":"Tonk Road",
   "city":"Jaipur", "state":"RJ", "zip":"176114","location":[26.8535922,75.7923988],
   "fees":2500, "tags":["Well equipped labs"], "rating":"4.5"
}

Sau đây mình sẽ giới thiệu một số loại query thường được sử dụng.

Match all query

Câu truy vấn chỉ đơn giản trả về tất cả các document, và tất cả có _score1.0.

Ví dụ:

GET /schools_search
{
    "query": {
        "match_all": {}
    }
}

Kết quả:

Match query

Trả về các documents phù hợp với giá trị text, number, date hay boolean mà ta cung cấp. Nếu field cần tìm kiếm là text thì sẽ được analyze trước khi tìm kiếm.

Ví dụ về match query:

GET schools/_search
{
    "query": {
        "match" : {
            "description" : {
                "query" : "state Board"
            }
        }
    }
}

Kết quả:

Match query hoạt động như thế nào? Đầu tiên, text được analyze, kết quả thu được sẽ sử dụng để xây dựng nên một truy vấn boolean. Tham số operator có thể được đặt là and hoặc or (mặc định là or). Nếu là or thì sẽ tìm các document mà chỉ cần chứa 1 trong các text thu được sau bước analyze, còn là and thì sẽ tìm các document chứa tất cả text thu được.

Ngoài ra còn rất nhiều các tham số khác sử dụng trong các trường hợp phức tạp mình không giới thiệu ở đây, bạn có thể đọc thêm ở https://www.elastic.co/guide/en/elasticsearch/reference/7.6/query-dsl-match-query.html

Multi-match query

Multi-match query được xây dựng dựa trên match query và cho phép truy vấn với nhiều field.

Ví dụ:

GET schools/_search
{
  "query": {
    "multi_match" : {
      "query":    "tonk road dawarka", 
      "fields": [ "street", "city" ] 
    }
  }
}

Kết quả:

Các field có thể được chỉ định sử dụng wildcards, ví dụ *_name thì các field được tìm kiếm sẽ là first_name, last_name.

Mỗi field riêng lẻ có thể tăng trọng số sử dụng (^):

GET /_search
{
  "query": {
    "multi_match" : {
      "query" : "this is a test",
      "fields" : [ "subject^3", "message" ] 
    }
  }
}

Ở truy vấn trên, field subject có độ quan trọng gấp 3 lần so với field message.

Query string query

Loại query này sẽ phân tích chuỗi truy vấn sử dụng trình phân tích cú pháp. Tức là chuỗi mà ta truyền vào phải viết chuẩn cú pháp, nếu chuỗi truy vấn chứa cú pháp không hợp lệ thì sẽ trả về lỗi.

Ví dụ query string:

GET schools/_search
{
  "query": {
      "query_string" : {
        "query" : "(state board) AND (affiliation)",
        "default_field" : "description"
      }
  }
}

Kết quả:

Ở đây, query là chuỗi truy vấn ta muốn phân tích cú pháp và sử dụng để tìm kiếm. default_field là field sẽ được thực hiện tìm kiếm nếu trong chuỗi truy vấn không cung cấp field mà ta muốn tìm kiếm trên đó.

Khi chạy truy vấn trên, query_string query tách (new york city) OR (big apple) thành 2 phần: new york citybig apple và được analyze độc lập với nhau.

Về cú pháp của chuỗi truy vấn có thể đọc thêm ở đây

Term query

Trả về các document mà field được chỉ định có giá trị đúng bằng term truyền vào.

Term query được dùng đề tìm kiếm document dựa trên giá trị chính xác như giá tiền, ID sản phẩm hay username.

Ví dụ:

GET schools/_search
{
  "query": {
    "term": {
        "fees": {
          "value": "2500"
        }
    }
  }
}

Kết quả:

Note: Tránh sử dụng term query trên text field vì mặc định Elasticsearch sẽ thay đổi giá trị của text field trong quá trình analysis làm cho việc tìm kiếm giá trị chính xác của text field sẽ khó.

Ví dụ: standard analyzer thay đổi giá trị của text field như sau:

  • Loại bỏ hầu hết các dấu chấm câu.
  • Chia nội dung còn lại thành các phần riêng lẻ gọi là token.
  • Chuyển token về dạng chữ thường.

Do term query không thực hiện analyze search term nên kết quả tìm kiếm có thể không như mong muốn.

VÍ dụ tìm kiếm một schoolfirst_name là "Saint Paul". Vì first_name là một text field, Elasticsearch sẽ thay đổi nó thành ["saint", "paul"] trong quá trình analysis, do đó first_name field sẽ không chứa chính xác term "Saint Paul". Term query trong trường hợp này sẽ không trả về kết quả nào:

Range query

Trả về các document chứa các term nằm trong phạm vi chỉ định.

Ví dụ:

GET schools/_search
{
  "query": {
    "range" : {
        "fees" : {
          "gte" : 1000,
          "lte" : 3000
        }
    }
  }
}

Query trên trả về các document có field fees có giá trị giữa 1000 và 3000.

Tham số của range<field> (field mà bạn muốn tìm kiếm trên đó).

Các tham số của <field> (mình chỉ liệt kê các tham số cơ bản thường dùng):

gt: Lớn hơn.

gte: Lớn hơn hoặc bằng.

lt: Nhỏ hơn.

lte: Nhỏ hơn hoặc bằng.

Note: Khi sử dụng range query với date field, bạn có thể sử dụng date math với 4 tham số ở trên. Ví dụ: truy vấn sau đây trả về các document có timestamp có giá trị ngày giữa hôm qua và hôm nay.

GET /_search
{
    "query": {
        "range" : {
            "timestamp" : {
                "gte" : "now-1d/d",
                "lt" :  "now/d"
            }
        }
    }
}

Boolean query

Boolean query là một ví dụ của compound query clause. Nó được sử dụng để kết hợp nhiều mệnh đề query khác sử dụng toán tử boolean. Mỗi mệnh đề có kiểu sau:

must: tương ứng với toán tử AND, document phải phù hợp với tất cả query bên trong must và có tính score.

filter: document phải phù hợp với tất cả query bên trong filter. mệnh đề filter được thực thi trong filter context nên score sẽ được bỏ qua và mệnh đề được xem xét để cache.

should: tương ứng với toán tử OR, document phù hợp với 1 trong các query bên trong should.

must_not: tương ứng với toán tử NOT, document phải không phù hợp với tất cả các query bên trong must_not

Ví dụ:

POST _search
{
  "query": {
    "bool" : {
      "must" : {
        "term" : { "user" : "kimchy" }
      },
      "filter": {
        "term" : { "tag" : "tech" }
      },
      "must_not" : {
        "range" : {
          "age" : { "gte" : 10, "lte" : 20 }
        }
      },
      "should" : [
        { "term" : { "tag" : "wow" } },
        { "term" : { "tag" : "elasticsearch" } }
      ],
      "minimum_should_match" : 1,
      "boost" : 1.0
    }
  }
}

Tóm tắt

Qua bài viết này mình đã giới thiệu ở mức cơ bản những query thông dụng thường được sử dụng trong Elasticsearch. Ngoài ra còn rất nhiều query khác và cách sử dụng phức tạp hơn của những query mình đã nêu ở trên, các bạn có thể tìm hiểu thêm ở link mình để bên dưới phần tham khảo.

Tham khảo

https://www.elastic.co/guide/en/elasticsearch/reference/7.6/query-dsl.html


All Rights Reserved