0

Elasticsearch Bài học 19: Giải phẫu Text Analysis - Character Filters, Tokenizer và Token Filters

Ở các bài trước, chúng ta thường ví von Analyzer (Bộ phân tích) như một "chiếc máy xay thịt". Bạn bỏ một câu văn bản nguyên vẹn (như "Sữa rửa mặt Cetaphil") vào một đầu, đầu kia nó nhả ra các "cục thịt băm" (Tokens) để xếp vào Inverted Index.

Nhưng nếu chỉ coi nó là một chiếc hộp đen, bạn sẽ không bao giờ hiểu tại sao khách gõ "H&M" lại ra kết quả của "H M", hay tại sao tìm "iPhone 15" lại ra cả đống ốp lưng.

Hôm nay, chúng ta sẽ mở nắp chiếc hộp đen này ra. Thực chất, mọi Analyzer trong Elasticsearch đều là một Pipeline (Luồng xử lý) tuân thủ quy trình lắp ráp gồm đúng 3 công đoạn chạy nối tiếp nhau.

1. Công đoạn 1: Character Filters (Tiền xử lý văn bản)

Trước khi băm văn bản thành các từ rời rạc, Elasticsearch cho phép bạn dọn dẹp "rác" trong chuỗi nguyên thủy. Một Analyzer có thể có không có, hoặc có nhiều Character Filters chạy nối tiếp nhau.

Nhiệm vụ của nó là Thêm, Sửa, hoặc Xóa các ký tự.

Các Character Filters phổ biến:

  • html_strip: Rất hữu ích khi bạn cào dữ liệu (crawl) từ website. Nó lột sạch các thẻ HTML. Ví dụ: "<p>Sữa rửa mặt <b>Cetaphil</b></p>" -> biến thành "Sữa rửa mặt Cetaphil".

  • mapping: Cho phép bạn cấu hình một từ điển thay thế ký tự. Ví dụ: biến & thành và, biến :) thành _smile_.

  • pattern_replace: Dùng Regex (Biểu thức chính quy) để thay thế phức tạp hơn. Ví dụ: xóa toàn bộ các số điện thoại có trong phần mô tả sản phẩm để chống lộ thông tin.

2. Công đoạn 2: Tokenizer (Cỗ máy tách từ)

Đây là trái tim của Analyzer. Khác với Filter, một Analyzer bắt buộc phải có và chỉ được phép có ĐÚNG 1 Tokenizer.

Nhiệm vụ duy nhất của nó là nhận chuỗi văn bản đã được dọn dẹp từ Bước 1, và "chặt" nó ra thành một mảng các từ đơn (Tokens). Đồng thời, Tokenizer cũng sẽ ghi nhận vị trí (position) của từng từ để phục vụ cho các truy vấn tìm kiếm theo cụm từ (match_phrase).

Các Tokenizer kinh điển:

  • standard (Mặc định): Cắt từ dựa trên dấu cách (khoảng trắng) và dấu câu (chấm, phẩy, gạch nối). Nó sẽ cắt chữ "H&M" thành ["H", "M"] (do coi & là dấu câu).

  • whitespace: Dễ chịu hơn, nó CHỈ cắt khi gặp dấu cách. Chữ "H&M" vẫn được giữ nguyên là ["H&M"].

  • uax_url_email: Giống hệt standard, nhưng nó đủ thông minh để nhận diện và không cắt nát các địa chỉ Email hoặc đường link URL.

3. Công đoạn 3: Token Filters (Hậu xử lý Tokens)

Sau khi Tokenizer chặt câu thành một mảng các Tokens, mảng này sẽ được đưa qua khâu kiểm duyệt cuối cùng. Một Analyzer có thể có không có, hoặc có rất nhiều Token Filters.

Nhiệm vụ của nó là biến đổi (VD: viết hoa thành viết thường), thêm mới (VD: thêm từ đồng nghĩa), hoặc xóa bỏ (VD: xóa từ vô nghĩa) các token.

Các Token Filters lợi hại nhất trong E-commerce:

  • lowercase: Biến mọi token thành chữ thường. Nhờ có nó, user gõ "IPHONE" hay "iphone" đều match vào Inverted Index.

  • stop (Stopwords): Xóa bỏ các từ nối vô nghĩa không mang giá trị tìm kiếm (VD trong tiếng Anh là a, an, the, and, or, is).

  • synonym (Từ đồng nghĩa): Vũ khí tối thượng của ngành bán lẻ. Nếu token là ["laptop"], filter này có thể tự động đẻ thêm token ["máy tính xách tay"] đặt vào Inverted Index. Khách gõ từ nào cũng trúng.

  • stemmer (Lấy từ gốc): Chủ yếu dùng cho tiếng Anh/Pháp/Đức. Nó gọt bỏ các hậu tố. Ví dụ: running, runs, ran đều quy về token gốc là run.

4. Thực hành: API _analyze (Chiếc máy X-Quang soi Token)

Khi hệ thống search không ra kết quả như ý, đừng vội sửa code. Hãy dùng API _analyze trên Kibana Dev Tools để chụp X-Quang xem Elasticsearch đã băm câu chữ của bạn như thế nào.

Hãy thử chạy lệnh sau với Analyzer mặc định (standard):

JSON

POST _analyze
{
  "analyzer": "standard",
  "text": "Mua 1 tặng 1 Áo thun nam H&M!"
}

Kết quả trả về sẽ cho bạn thấy quá trình chặt từ cực kỳ rõ ràng:

  1. Nó bỏ dấu ! và dấu &.

  2. Biến chữ M, Á, H thành chữ thường.

  3. Chặt mảng thành: ["mua", "1", "tặng", "1", "áo", "thun", "nam", "h", "m"].

(Thử tưởng tượng: Với tập token này, nếu khách gõ "H&M", họ sẽ được Elasticsearch cho match với token h và token m. Nhưng nếu khách gõ "Áo chữ H", họ cũng bị match với token h. Kết quả search sẽ cực kỳ nhiễu loạn).

Cấu trúc lại luồng đi: Nếu bạn hiểu rõ 3 bước này, khi đối mặt với bài toán nhiễu loạn trên, bạn sẽ biết cách giải quyết:

  • "À, do Tokenizer standard tự cắt mất dấu &. Vậy mình sẽ thêm một Character Filter mapping ở Bước 1, ép đổi H&M thành hm_brand. Hoặc mình sẽ đổi Tokenizer ở Bước 2 thành whitespace".

Để làm được điều đó (lắp ráp một Character Filter của riêng mình, nối với Tokenizer mình chọn, và bồi thêm Synonym Token Filter), chúng ta sẽ cần vứt bỏ Analyzer mặc định và tự tay build một Custom Analyzer.


All Rights Reserved

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