0

Tuyệt chiêu "Should" trong Elasticsearch: Nghệ thuật chiều lòng những khách hàng tìm kiếm "nửa vời"

Chào anh em Viblo, lại là mình đây!

Nếu anh em làm backend cho các hệ thống thương mại điện tử hoặc các ứng dụng đòi hỏi tính năng tìm kiếm (Search) mạnh mẽ, chắc chắn không thể bỏ qua Elasticsearch. Trong các bài trước, chúng ta đã lặn ngụp với Nested Query hay Script Query để giải quyết logic vặn vẹo. Hôm nay, mình muốn rẽ hướng sang một thứ nhẹ nhàng hơn về mặt logic nhưng lại mang tính "sống còn" đối với trải nghiệm người dùng (UX): Query String với mệnh đề should.

Trong quá trình tối ưu hóa hệ thống search cho Hasaki, team mình từng đối mặt với một bài toán cực kỳ kinh điển: Làm sao để trả về kết quả tìm kiếm vừa chính xác, lại vừa "bao dung" với những cú pháp tìm kiếm vô chừng của khách hàng? Và mệnh đề should chính là chiếc chìa khóa vàng.

1. Vấn đề: Khi "MUST" (Bắt buộc) trở nên quá cứng nhắc

Trong Elasticsearch, mệnh đề must hoạt động hệt như phép AND trong SQL. Nghĩa là, điều kiện bạn đưa ra bắt buộc phải thỏa mãn 100%.

Giả sử khách hàng gõ từ khóa: "sữa rửa mặt la roche posay cho da mụn". Nếu bạn nhét toàn bộ đống này vào một mệnh đề must (hoặc toán tử AND), Elasticsearch sẽ tìm kiếm những sản phẩm chứa đầy đủ các từ: "sữa", "rửa", "mặt", "la", "roche", "posay", "cho", "da", "mụn".

Chỉ cần sản phẩm thiếu chữ "cho" hoặc "da", nó sẽ bị loại thẳng tay khỏi kết quả. Khách hàng sẽ nhận được một trang trắng bóc kèm dòng chữ vô cảm: "Không tìm thấy sản phẩm nào". Chắc chắn bạn vừa đánh rơi một đơn hàng!

2. Sự xuất hiện của "SHOULD": Linh hoạt và tinh tế

Để hệ thống search trở nên "người" hơn, chúng ta cần một cơ chế đánh giá độ ưu tiên (Scoring) thay vì chỉ gạt bỏ trắng đen (Matching). Mệnh đề should trong bool query sinh ra làm nhiệm vụ đó. Nó hoạt động giống như toán tử OR, nhưng có thêm phép thuật cộng điểm.

Logic lúc này sẽ chuyển thành:

  • Sẽ rất tuyệt nếu sản phẩm có chứa từ "la roche posay" (Cộng nhiều điểm).
  • Sẽ rất tốt nếu nó là "sữa rửa mặt" (Cộng điểm).
  • Nếu có thêm chữ "da mụn" thì càng hoàn hảo (Cộng thêm điểm và đẩy lên top 1).
  • Nhưng nếu nó chỉ là "sữa rửa mặt la roche posay" thôi (không có chữ da mụn), thì vẫn cho nó xuất hiện ở top dưới nhé, đừng ẩn nó đi.

Hãy xem cấu trúc query sau:

{
  "query": {
    "bool": {
      "should": [
        { "match": { "name": "sữa rửa mặt" } },
        { "match": { "brand": "la roche posay" } },
        { "match": { "attributes": "da mụn" } }
      ]
    }
  }
}

Bất kỳ sản phẩm nào thỏa mãn ít nhất MỘT trong các điều kiện trên đều sẽ được hiển thị. Sản phẩm nào thỏa mãn CÀNG NHIỀU điều kiện thì điểm số (Relevance Score - _score) càng cao và sẽ trồi lên trên cùng. Khách hàng có gõ thiếu, gõ lộn xộn, họ vẫn thấy được thứ gần đúng nhất với nhu cầu của mình.

3. "minimum_should_match": Dây cương kiểm soát sự tự do

Tuy should rất tuyệt, nhưng nếu bạn thả cửa hoàn toàn, thảm họa sẽ xảy ra.

Ví dụ khách gõ: "sữa rửa mặt", hệ thống có thể trả về cả... "sữa tắm", "sữa tươi", hay "mặt nạ" chỉ vì chúng vô tình có chứa từ "sữa" hoặc "mặt" (thỏa mãn điều kiện OR). Khách hàng sẽ thấy hệ thống search của bạn thật ngớ ngẩn.

Để khắc phục, chúng ta dùng tham số minimum_should_match. Nó quy định: "Okay, tôi cho phép dùng OR để tìm kiếm linh hoạt, nhưng ít nhất phải khớp bao nhiêu phần trăm từ khóa thì mới được tính là hợp lệ".

{
  "query": {
    "match": {
      "name": {
        "query": "sữa rửa mặt la roche posay",
        "operator": "or",
        "minimum_should_match": "75%"
      }
    }
  }
}

Với minimum_should_match: "75%", nếu người dùng gõ 4 từ, ít nhất 3 từ phải xuất hiện trong sản phẩm thì Elasticsearch mới trả về kết quả. Bằng cách này, bạn vừa giữ được sự linh hoạt (không khắt khe như must), vừa đảm bảo kết quả không bị "rác".

4. Bơm "Steroid" cho từ khóa với Boost

Một tuyệt chiêu nữa mình hay dùng chung với should là Boosting (Tăng trọng số). Trong một câu query, không phải thuộc tính nào cũng quan trọng như nhau. Ví dụ: Từ khóa xuất hiện trong tên sản phẩm (name) phải có giá trị gấp 3 lần so với việc nó xuất hiện ở phần mô tả (description).

{
  "query": {
    "bool": {
      "should": [
        { "match": { "name": { "query": "sữa rửa mặt", "boost": 3 } } },
        { "match": { "description": { "query": "sữa rửa mặt", "boost": 1 } } }
      ]
    }
  }
}

Lúc này, những sản phẩm có chữ "sữa rửa mặt" ngay ở tiêu đề sẽ được buff điểm cực mạnh để chiếm lấy vị trí Top đầu, đẩy những sản phẩm chỉ nhắc phớt qua ở phần mô tả xuống dưới.

Lời kết

Xây dựng hệ thống Search không chỉ là câu chuyện của Indexing nhanh hay chậm, mà phần lớn là câu chuyện của UX: Hiểu được ý định thực sự của người dùng đằng sau những dòng text họ gõ. Kết hợp khéo léo giữa must (để bóp hẹp phạm vi chính xác) và should (để sắp xếp độ ưu tiên linh hoạt) chính là nghệ thuật để tạo ra một thanh tìm kiếm "biết chiều lòng người".

Hệ thống search của anh em đang được thiết kế thế nào? Có mẹo nào hay ho để tinh chỉnh điểm số trong Elasticsearch không? Bình luận bên dưới để cùng chém gió nhé!


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.