Tìm kiếm trong Elasticsearch có thể được coi là một domain lớn trong ngành IT hiện nay. DSL được coi là giải pháp tìm kiếm toàn diện nhưng cũng không kém phần phức tạp mà Elasticsearch cung cấp cho chúng ta sử dụng. Nó cho phép chúng ta thực hiện hóa được nhiều câu tìm kiếm từ đơn giản đến phức tạp, từ một điều kiện đến kết hợp nhiều điều kiện lại với nhau. Trong bài viết tiếp theo của series Elasticsearch, Stringee và các bạn sẽ cùng nhau tìm hiểu về loại truy vấn cực kỳ thú vị và hữu dụng này nhé.

>>> Xem thêm bài viết trong chuỗi bài hướng dẫn tìm hiểu ngôn ngữ lập trình Elasticsearch:

1. Truy vấn DSL là gì?

DSL là viết tắt của Domain Specific Language, được dựa trên kiểu dữ liệu JSON để định nghĩa các câu truy vấn. Từ DSL, ta có thể liên tưởng đến AST (Abstract Syntax Tree) hay còn được gọi là một cây truy vấn trừu tượng bao gồm hai mệnh đề:

  • Leaf query clauses (các câu truy vấn lá): tìm kiếm cho một giá trị cụ thể của một trường cụ thể, ở đây chúng ta có thể sử dụng các truy vấn match, term hoặc range.
  • Compound query clauses (các mệnh đề truy vấn kết hợp): các truy vấn kết hợp này cho phép chúng ta đóng gói các truy vấn lá khác hoặc các truy vấn kết hợp khác và được sử dụng để kết nối nhiều câu truy vấn trong một mối quan hệ logic như là bool hay dis_max hoặc để thay thế cho biểu hiện của chúng như truy vấn constant_score.

2. Mệnh đề truy vấn lá

Tại đây, chúng ta sẽ cùng nhau đi tìm hiểu về một vài câu truy vấn lá thông dụng được Elasticsearch cung cấp. Đầu tiên trong danh sách này là truy vấn match.

2.1. Truy vấn match

Sử dụng truy vấn này sẽ trả về cho chúng ta các document trùng khớp với đoạn ký tự tìm kiếm, số hay các giá trị đúng/sai. Ở đây, từ khóa tìm kiếm sẽ được phân tích trước khi đưa ra so sánh.

Câu truy vấn match là truy vấn cơ bản trong việc thực hiện một quá trình full-text-search, bao gồm cả các lựa chọn khớp với từ khóa tìm kiếm lộn xộn.

Truy vấn match có thể được sử dụng như sau:

GET index-01/_search
{
  "query": {
    "match": {
      "_id": "i5IEpYsB-XeRF7h4FTkP"
    }
  }
}

2.2. Truy vấn term

Truy vấn này sẽ trả về các document chứa từ khóa tìm kiếm một cách chính xác. Chúng ta có thể sử dụng truy vấn term để tìm kiếm các document dựa trên một thông tin đã được xác định từ trước như là một ID của sản phẩm hoặc một username.

GET index-01/_search
{
  "query": {
    "term": {
      "name.keyword": {
        "value": "John Doe",
        "boost": 1.0
      }
    }
  }
}

Ở đây chúng ta có một ví dụ sử dụng để tìm kiếm trong index mà ta đã tạo từ trước. 

<field>: field muốn thực hiện tìm kiếm

Các biến tìm kiếm cho <field>

value: là một trường bắt buộc để tìm kiếm cho trường được định nghĩa trong <field>. Để trả về một document, giá trị term bắt buộc phải match với giá trị field tìm kiếm, bao gồm cả khoảng trắng và ký tự viết hoa.

boost: là thông tin tìm kiếm không bắt buộc được sử dụng để giảm hay tăng giá trị điểm đánh giá độ liên quan của một truy vấn. Mặc định là 1.0.

Bạn có thể sử dụng biến boost để điều chỉnh điểm tương đồng phục vụ cho việc tìm kiếm cho hai hay nhiều hơn các truy vấn.

2.3. Truy vấn range

Cho phép tìm kiếm các document có chứa các giá trị tìm kiếm thuộc trong một khoảng tìm kiếm. Cú pháp tìm kiếm cho truy vấn này có thể được tham khảo từ ví dụ dưới đây:

GET /_search
{
  "query": {
    "range": {
      "age": {
        "gte": 10,
        "lte": 20,
        "boost": 2.0
      }
    }
  }
}

Trong truy vấn này, ngoài field luôn là trường mà chúng ta cần tìm kiếm thì các biến sau sẽ cần được chú ý để có thể tạo được các truy vấn phù hợp với nhu cầu sử dụng của mình.

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

format: định dạng ngày tháng được sử dụng để chuyển đổi giá trị date trong query

>>> Xem thêm bài viết:

Tìm hiểu về ràng buộc (Constraint) trong SQL

Tìm hiểu về cơ sở dữ liệu phi quan hệ MongoDB

Sử dụng map reduce trong MongoDB

3. Câu truy vấn kết hợp

3.1. Kết hợp truy vấn với bool

Là một loại truy vấn trả về kết quả là các document tương thích với kết quả kết hợp của nhiều truy vấn với nhau. Truy vấn này tương thích với truy vấn BooleanQuery của Lucene. Nó được sử dụng để xây dựng lên một hoặc nhiều các mệnh đề đúng/sai, mỗi mệnh đề có một kiểu thể hiện khác nhau. Các kiểu thể hiện này gồm có:

  • must: câu truy vấn tìm kiếm bắt buộc các điều kiện tìm kiếm phải đúng, nó sẽ đóng góp vào điểm tìm kiếm của truy vấn.
  • filter: mệnh đề truy vấn bắt buộc phải xuất hiện trong các document match với nó. Tuy nhiên, khác với must, giá trị score (điểm) của truy vấn filter sẽ không được sử dụng đến. Các mệnh đề filter sẽ được thực hiện trong filter context, điều này có nghĩa là việc tính điểm sẽ không được quan tâm và được đánh giá là sử dụng cho việc cache.
  • should: truy vấn cho biết một trong các điều kiện của nó nên xuất hiện trong các document match với nó.
  • must_not: ngược lại với must. Các truy vấn có dạng này sẽ ép buộc giá trị tìm kiếm trả về các kết quả không tương thích với nó.

Dưới đây là một truy vấn bao gồm các lá được gom lại với nhau bằng truy vấn bool:

GET index-01/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "John"
          }
        }
      ],
      "filter": [
        {
          "match": {
            "email": "john.doe@gmail.com"
          }
        }
      ],
      "must_not": [
        {
          "range": {
            "age": {
              "gte": 10,
              "lte": 18
            }
          }
        }
      ],
      "should": [
        {
          "match": {
            "name": "Doe"
          }
        },
        {
          "match": {
            "name": "John"
          }
        }
      ],
      "minimum_should_match": 1,
      "boost": 1
    }
  }
}

Trong khi kết hợp nhiều mệnh đề với nhau, chúng ta còn có thể sử dụng minimum_should_match để chỉ ra số số phần trăm các truy vấn nằm trong mệnh đề should cần match để trả về kết quả tìm kiếm.

3.2. Kết hợp truy vấn với dis_max

Trả về số document match một hay nhiều hơn các truy vấn được wrap lại với nhau, đây được gọi là các mệnh đề truy vấn.

Nếu một document được trả về match với nhiều mệnh đề truy vấn, câu tìm kiếm dis_max sẽ gán document có điểm đánh giá liên quan cao nhất từ bất kỳ mệnh đề nào, cộng thêm với giá trị tie_break cho bất kỳ các truy vấn con nào trong nó match với kết quả trả về.

GET /_search
{
  "query": {
    "dis_max": {
      "queries": [
        { "term": { "title": "Quick pets" } },
        { "term": { "body": "Quick pets" } }
      ],
      "tie_breaker": 0.7
    }
  }
}

3.3. Thay đổi hành vi tìm kiếm với constant_score

Truy vấn này sẽ gói một truy vấn filter và trả về bất cứ document nào tương thích với điểm được đánh giá so với truy vấn bằng giá trị boost:

GET index-01/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "match": {
          "email": "john.doe@gmail.com"
        }
      },
      "boost": 1.2
    }
  }
}

4. Các truy vấn phức tạp

Một số loại truy vấn sẽ được xử lý chậm hơn tùy theo cách chúng được phát triển, điều này có thể gây ảnh hưởng tới tính ổn định của cluster. Dưới đây là một số truy vấn các bạn có thể tìm hiểu thêm nhé:

  • script: lọc các document dựa trên một đoạn script
  • Các truy vấn trên các trường loại số, date, boolean, ip, geo_point hoặc keyword
  • Truy vấn fuzzy: loại trừ việc thực hiện trên các trường wildcard
  • Truy vấn regex: loại trừ việc thực hiện trên các trường wildcard
  • Truy vấn prefix: loại trừ việc thực hiện trên các trường wildcard
  • Truy vấn wildcard: loại trừ việc thực hiện trên các trường wildcard
  • Truy vấn range trên các trường có loại text hoặc keyword
  • Các truy vấn cho phép join: script join, percolate

Kết bài

Vừa rồi là những chia sẻ của Stringee về DSL trong Elasticsearch, trong thời gian tới, Stringee sẽ còn đem đến cho bạn đọc nhiều kiến thức hơn nữa về chủ đề này. Các bạn hãy cùng đón đọc để học hỏi thêm những thông tin hữu ích mới nhé.


Stringee Communication APIs là giải pháp cung cấp các tính năng giao tiếp như gọi thoại, gọi video, tin nhắn chat, SMS hay tổng đài CSKH cho phép tích hợp trực tiếp vào ứng dụng/website của doanh nghiệp nhanh chóng. Nhờ đó giúp tiết kiệm đến 80% thời gian và chi phí cho doanh nghiệp bởi thông thường nếu tự phát triển các tính năng này có thể mất từ 1 - 3 năm.

Bộ API giao tiếp của Stringee hiện đang được tin dùng bởi các doanh nghiệp ở mọi quy mô, lĩnh vực ngành nghề như TPBank, VOVBacsi24, VNDirect, Shinhan Finance, Ahamove, Logivan, Homedy,  Adavigo, bTaskee…

Quý bạn đọc quan tâm xin mời đăng ký NHẬN TƯ VẤN TẠI ĐÂY: