+2

[ Phần 2 ] Các loại Query trong ElasticSearch

Các Loại Tìm Kiếm Trong Elasticsearch

Elasticsearch không chỉ mạnh mẽ mà còn cực kỳ linh hoạt! Hôm nay, hãy cùng mình khám phá các loại query phổ biến giúp bạn tìm kiếm dữ liệu nhanh như chớp nhé! 🚀


Mục lục:

  1. Phân trang trong ElasticSearch
  2. Sort trong ElasticSearch
  3. Match Query (Tìm kiếm gần đúng)
  4. Term Query
  5. Bool Query
  6. Range Query
  7. Exists Query
  8. Wildcard Query
  9. Prefix Query
  10. Fuzzy Query
  11. Aggregations Query ( Phân tích dữ liệu )
  12. Multi-field Search
  13. Bảng so sánh các loại query trong bài viết

Dưới đây là một file dữ liệu mẫu , hãy mở ra, insert vào hệ thống ES của bạn và cùng thực hành với mình nhé ♥️

https://docs.google.com/document/d/1AIJDu3lWY1adSIKedyHIsKhkCfgUX5qw1dM1kfQ3648/edit?tab=t.0

Các Loại Tìm Kiếm Trong Elasticsearch

# Cú pháp : POST <index_name>/_search

1. Phân Trang Trong Elasticsearch

Trường hợp Nên dùng
Phân trang nhỏ (< 10,000 bản ghi) from + size
Phân trang lớn (> 10,000 bản ghi) search_after
Truy xuất dữ liệu hàng loạt scroll API

1.1. Cách sử dụng fromsize

🔹 Giới hạn mặc định của size : ELK mặc định chỉ cho phép lấy tối đa 10.000 bản ghi (index.max_result_window = 10000)

🔹 Nếu from quá lớn ( vd : from : 10000 ), elk vẫn phải duyệt qua các bản ghi trước đó, gây ảnh hưởng đến hiệu suất

{
  "from": 1,
  "size": 5,
  "query": {
    "query_string": {
      "query": "*"
    }
  }
}

1.2. Cách sử dụng search_after

{
  "size": 5,
  "sort": [{ "weight": "asc" }],
  "search_after": [69]
}

📌 Cách hoạt động::

  • Lấy 5 bản ghi đầu tiên
  • Order theo weight ASC ( bắt buộc phải có order )
  • Dùng giá trị weight cuối cùng để làm search_after trong lần truy vấn tiếp theo  Order theo weight ASC, lấy 5 bản ghi đầu tiên, bắt đầu từ bản ghi có weight = 69

🍎 Phân biệt from với search_after

Tiêu chí from + size search_after
Cách hoạt động Bỏ qua from bản ghi đầu tiên Dựa vào giá trị của sort để lấy tiếp
Hiệu suất Giảm khi from quá lớn Tốt hơn cho dữ liệu lớn
Giới hạn Mặc định tối đa 10,000 bản ghi Không giới hạn

1.3. Cách sử dụng scroll API

🔹 Dùng để lấy dữ liệu hàng loạt mà không bị giới hạn from.

{
  "size": 1000,
  "query": {
    "match_all": {}
  },
  "scroll": "1m"
}

📌 Lưu ý: Scroll phù hợp với lấy dữ liệu hàng loạt, không dùng cho phân trang thông thường.


2. Sort Trong Elasticsearch

Loại Sort Payload đầy đủ Dùng khi nào?
Sắp xếp theo một trường { "sort": [ { "salary": "desc" } ] } Khi cần sắp xếp theo một tiêu chí duy nhất.
Sắp xếp theo nhiều trường { "sort": [ { "team.keyword": "asc" }, { "salary": "desc" } ] } Khi cần phân loại theo nhiều tiêu chí.
Sắp xếp với giá trị null { "sort": [ { "careerEnd": { "order": "asc", "missing": "_last" } } ] } Khi dữ liệu có thể bị thiếu giá trị.
Sắp xếp trên trường text { "sort": [ { "nationality.keyword": "asc" } ] } Khi sắp xếp theo text (cần .keyword).
Sắp xếp theo công thức { "sort": [ { "_script": { "source": "doc['goals'].value * 2 + doc['assists'].value" } } ] } Khi cần sắp xếp dựa trên công thức tùy chỉnh.

📌 Ghi chú quan trọng:

  1. Trường text cần .keyword để sắp xếp. => Nếu muốn sắp xếp theo tên, dùng name.keyword, không dùng name.
  2. Dữ liệu thiếu giá trị (null) có thể bị lỗi khi sắp xếp. => Dùng "missing": "_last" hoặc "missing": "_first" để xử lý.
  3. Sử dụng script có thể chậm hơn. => Chỉ dùng khi không thể lưu giá trị sắp xếp trong index.

3. Match Query (Tìm kiếm gần đúng)

🔹Dùng khi muốn tìm kiếm văn bản mà không cần khớp chính xác. Nó là loại search phổ biến nhất trong Elasticsearch.

🔹 Hữu ích khi tìm kiếm full-text

{
  "query": {
    "match": {
      "name": "Messi"
    }
  }
}
  • Giải thích: Tìm tất cả các tài liệu có chứa từ "Messi" trong trường "name".

4. Term Query (Tìm kiếm chính xác)

🔹 Dùng khi muốn tìm kiếm giá trị chính xác ( không phân tích từ khoá )

🔹 Tốt cho trường hợp tìm kiếm số, ID, hoặc từ khóa cố định.

{
  "query": {
    "term": {
      "team.keyword": "Real Madrid"
    }
  }
}

5. Bool Query (Tìm kiếm kết hợp nhiều điều kiện)

🔹 Cho phép tìm kiếm với các điều kiện must (phải có), should (nên có), must_not (không được có), filter (lọc không ảnh hưởng đến scoring).

  • Ví dụ: Tìm cầu thủ cao trên 1.8m, lương trên 40 triệu USD, và không phải đội "Inter Miami".
{
  "query": {
    "bool": {
      "must": [
        { "range": { "height": { "gt": 1.8 } } },
        { "range": { "salary": { "gt": 40000000 } } }
      ],
      "must_not": [
        { "term": { "team": "Inter Miami" } }
      ]
    }
  }
}
  • Giải thích:

    • must: cầu thủ phải thỏa điều kiện.

    • must_not: loại bỏ cầu thủ của "Inter Miami".

    • range: lọc theo giá trị số (gt = lớn hơn).

6. Range Query (Tìm kiếm theo khoảng giá trị)

🔹 Tìm kiếm theo khoảng số

{
  "query": {
    "range": {
      "careerStats.goals": {
        "gte": 500,
        "lte": 1000
      }
    }
  }
}
  • Giải thích: gte (>=), lte (<=) để xác định khoảng giá trị.

7. Exists Query

🔹 Tìm kiếm một trường có tồn tại hay không

  • Ví dụ: Tìm cầu thủ có thông tin trên Twitter.
{
 "query": {
   "exists": {
     "field": "socialMedia.twitter"
   }
 }
}

  • Giải thích: Trả về tài liệu có trường twitter tồn tại.

8. Wildcard Query (Tìm kiếm với ký tự đại diện)

🔹 Tìm kiếm với ký tự đại diện

🔹 Wildcard Query không hoạt động trên trường đã được phân tích (analyzed): Trong Elasticsearch, các trường dạng "text" (mặc định) bị phân tích (tokenized), trong khi Wildcard Query chỉ hoạt động trên "keyword".

  • Ví dụ: Tìm cầu thủ có tên bắt đầu bằng "Cris".
{
  "query": {
    "wildcard": {
      "name.keyword": "Cris*"
    }
  }
}

9. Prefix Query

🔹 Tìm kiếm theo tiền tố cụ thể

  • Ví dụ: Tìm cầu thủ có tên bắt đầu bằng "Ney".
{
  "query": {
    "prefix": {
      "name.keyword": "Ney"
    }
  }
}

  • Ghi chú: Prefix query hoạt động nhanh hơn wildcard query vì chỉ tìm tiền tố.

10. Fuzzy Query (Tìm kiếm mờ, sửa lỗi chính tả)

🔹Tìm kiếm với khả năng sửa lỗi chính tả.

{
  "query": {
    "fuzzy": {
      "name": {
        "value": "Ronalldo",
        "fuzziness": 2
      }
    }
  }
}
  • Giải thích: Hoạt động nhanh hơn wildcard query vì chỉ tìm tiền tố.

11. Aggregations Query (Phân tích dữ liệu)

🔹Tính toán và tổng hợp dữ liệu.

{
  "size": 0,
  "aggs": {
    "average_salary": {
      "avg": {
        "field": "salary"
      }
    }
  }
}
  • Giải thích: avg tính trung bình lương, size = 0 để chỉ lấy về • aggregations mà không cần dữ liệu chi tiết. Cải thiện hiệu năng

12. Multi-field Search (Tìm kiếm trên nhiều trường)

🔹Multi-field Search là kỹ thuật tìm kiếm trên nhiều trường ( fields ) cùng lúc trong ElasticSearch

Trường hợp Cách nên dùng
Tìm kiếm đơn giản trên nhiều trường ✅ multi_match
Tìm kiếm với toán tử nâng cao (AND, OR, *) ✅ query_string
Tìm kiếm có scoring và kết hợp nhiều điều kiện ✅ bool Query

12.1. Multi-fields Search với multi_match

🔹Dùng khi cần tìm kiếm trên nhiều trường cùng lúc.

  • Ví dụ: Tìm cầu thủ có tên "Messi" hoặc có đội bóng chứa từ "Miami".
{
  "query": {
    "multi_match": {
      "query": "Messi",
      "fields": ["name", "team"]
    }
  }
}

12.2. Multi-fields search với query_string

🔹Dùng khi cần toán tử nâng cao (AND, OR, *, ?)

  • Ví dụ: Tìm các bản ghi cầu thủ có cả Messi và Liverpool
{
 "query": {
   "query_string": {
     "query": "Messi OR Liverpool",
     "fields": ["name", "team"]
   }
 }
}

12.3. Multi-fields Search với bool_query

🔹Dùng khi cần tính điểm (scoring) và kết hợp nhiều điều kiện.

  • Ví dụ: Tìm cầu thủ có tên chứa "Messi" hoặc đội bóng là "Manchester City".
{
 "query": {
   "bool": {
     "should": [
       { "match": { "name": "Lionel Messi" } },
       { "match": { "team": "Macnhester City" } }
     ],
     "minimum_should_match": 1
   }
 }
}

📌Lưu ý : Elasticsearch sắp xếp kết quả theo mức độ liên quan (relevance score), nên nếu một tài liệu có điểm số thấp, nó có thể bị loại khỏi kết quả hiển thị.

=> Dùng minimum_should_match để đảm bảo lấy tất cả các bản ghi thỏa ít nhất 1 điều kiện


13. Bảng so sánh các loại query trong bài viết

Loại Query Khi nào nên dùng Ví dụ trên football_players
Match Query (Phù hợp từ khóa, có scoring) Khi tìm kiếm văn bản hoặc dữ liệu dạng chuỗi với phân tích từ khóa (phù hợp một phần). Tìm cầu thủ có tên chứa "Messi".
Term Query (Khớp chính xác) Khi cần tìm kiếm giá trị chính xác (không phân tích từ khóa).
Bool Query (Kết hợp nhiều điều kiện) Khi cần tìm kiếm phức tạp với điều kiện must, should, must_not, filter. Tìm cầu thủ có chiều cao > 1.8m, lương > 40 triệu USD, không thuộc "Inter Miami".
Range Query (Tìm kiếm theo khoảng giá trị) Khi cần lọc dữ liệu dựa trên số (lương, bàn thắng, chiều cao, v.v.). Tìm cầu thủ có số bàn thắng từ 500 đến 1000.
Exists Query (Kiểm tra trường có tồn tại) Khi muốn kiểm tra xem một tài liệu có chứa một trường nào đó không. Tìm cầu thủ có thông tin Twitter.
Wildcard Query (Tìm kiếm với ký tự đại diện) Khi tìm kiếm theo mẫu, cho phép ký tự đại diện * và ?. Chậm hơn prefix. Tìm cầu thủ có tên bắt đầu bằng "Cris*".
Prefix Query (Tìm theo tiền tố) Khi tìm kiếm chuỗi bắt đầu bằng một ký tự cụ thể. Nhanh hơn wildcard. Tìm cầu thủ có tên bắt đầu bằng "Ney".
Fuzzy Query (Tìm kiếm mờ, sửa lỗi chính tả) Khi tìm kiếm có thể có lỗi chính tả hoặc biến thể của từ. Tìm cầu thủ có tên gần đúng với "Ronalldo".
Aggregations Query (Phân tích, tổng hợp dữ liệu) Khi cần thống kê dữ liệu, tính trung bình, đếm, nhóm. Tính lương trung bình của tất cả cầu thủ.
Sorting Query (Sắp xếp kết quả) Khi cần hiển thị kết quả theo thứ tự tăng/giảm dần. Sắp xếp cầu thủ theo lương giảm dần.

14. Kết Luận

Elasticsearch cung cấp nhiều loại tìm kiếm mạnh mẽ, phù hợp với từng nhu cầu cụ thể như tìm kiếm chính xác, tìm kiếm gần đúng, tìm kiếm theo khoảng giá trị hoặc tìm kiếm nâng cao với nhiều điều kiện. Việc lựa chọn đúng loại query sẽ giúp tối ưu hiệu suất và độ chính xác của hệ thống tìm kiếm.

Hãy thực hành, trải nghiệm và đón chờ phần [Phần 3] của series này nhé !

Nếu các bạn thấy hữu ích, hãy ủng hộ tôi bằng 1 cái upvote nhé 😁

Cảm ơn quý các bạn đã đón xem 🥰

Link bài viết [Phần 1] : https://viblo.asia/p/phan-1-huong-dan-crud-voi-elasticsearch-m2vJPz2qVeK


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí