- vừa được xem lúc

[Phỏng vấn Backend]: Mô tả cách bạn sử dụng elasticsearch trong thực tế?

0 0 5

Người đăng: Hiếu học code

Theo Viblo Asia

1. Thiết kế Schema (mapping)

Phân tích dữ liệu và yêu cầu tìm kiếm

  • Xác định các trường dữ liệu chính cần lưu trữ. Trong trường hợp của tôi là một số trường của sản phẩm (id, tên, description) cùng với các nhà cung cấp (id, vị trí địa lý). Mục đích là tìm sản phẩm phù hợp nhất mà phí ship rẻ nhất cho người mua.

Cấu trúc document

Có nhiều cấu trúc để lựa chọn như:

  • Flat structure: Cấu trúc phẳng, đơn giản nhất
  • Nested objects: Cho phép lưu trữ mảng các object phức tạp
  • Parent-child relationships: Cho các mối quan hệ phức tạp giữa các entities

Do dữ liệu không quá nhiều nên tôi chọn loại flat structure.

Lựa chọn kiểu dữ liệu phù hợp

Có nhiều loại data type khác nhau để lựa chọn:

  • Text: Cho full-text search
  • Keyword: Cho exact matching và aggregations
  • Numeric types (long, integer, short, byte, double, float)
  • Date
  • Boolean
  • Geo-point và Geo-shape: Cho dữ liệu địa lý
  • IP: Cho địa chỉ IP

Với mình thì text cho sản phẩm và Geo-point cho vị trí cửa hàng là phù hợp nhất.

2. Indexing Strategy

Cấu hình analyzers và tokenizers

  • Standard analyzer: phân tích văn bản thành các từ, loại bỏ dấu câu, chuyển thành chữ thường.

  • Simple analyzer: phân tích văn bản dựa trên ký tự không phải chữ cái, chuyển thành chữ thường.

  • Whitespace analyzer: phân tích văn bản dựa trên khoảng trắng.

  • Language-specific analyzers: như english, french, etc.

Dự án mình không có gì đặc biệt lắm nên dùng loại thường này.

Tokenizers:

  • Standard tokenizer: phân tích văn bản thành các từ.
  • Whitespace tokenizer: phân tích dựa trên khoảng trắng.
  • NGram tokenizer: tạo n-grams từ văn bản.
  • Edge NGram tokenizer: tạo n-grams từ đầu của mỗi từ.

Mình chọn standard luôn vì.

Token filters:

  • Lowercase filter: chuyển đổi text thành chữ thường.
  • Stop words filter: loại bỏ các stop words.
  • Synonym filter: thêm các từ đồng nghĩa

3. Chiến lược reindexing và zero-downtime updates

3.1 Thay đổi nhỏ của data (insert, update, delete)

Có 2 cách mà mình nghĩ đến cho việc sync data giữa database chính (mình dùng postgres) với elasticsearch:

  • Chạy cronjob: sau một khoảng thời gian thì sẽ vô database xem có update gì mới không thì bỏ lên ES. Cách này thì đơn giản, nhưng không đảm bảo dữ liệu được đồng bộ ngay.
  • Trigger sự kiện thay đổi (trigger bằng WAL hoặc API trực tiếp), có thay đổi thì gửi yêu cầu update đến message queue -> backend service write elasticsearch sẽ nhận request và update lên ES. Cách này được cái sync riu time hơn nhưng tốn công làm.

3.2 Tạo index mới:

Do nhu cầu business có thay đổi nên mình phải sửa lại mapping của ES, lúc này mình xử lý như sau:

  • Tạo một index mới với mapping mới phù hợp với cấu trúc dữ liệu mới.
  • Sử dụng Reindex API để copy dữ liệu từ index cũ sang index mới.
  • Sử dụng alias để chuyển đổi traffic sang index mới. Ví dụ: products_v1 -> products_alias -> products_v2
  • Thực hiện rolling update cho đến khi hết traffic trong index cũ.
  • Đóng index cũ sau khi hoàn tất chuyển đổi.

Mặc dù chuyển xong nhưng không xoá ngay mà phải để một thời gian dài sau mình mới xoá để tránh tình trạng có vấn đề với index mới thì lại không có đường nào rollback. Việc quản lý vòng đời của index có thể sử dụng index lifecycle management (ILM) giúp lên kết hoạch xoá hoặc archive index cũ sau một thời gian nhất định.

4. Query Optimization

Sử dụng query DSL hiệu quả

Elasticsearch sử dụng một ngôn ngữ đặc biệt gọi là Query DSL (match, multi_match, bool, term) để xây dựng các truy vấn. DSL cung cấp rất nhiều loại truy vấn khác nhau, và việc chọn đúng loại truy vấn cho trường hợp cụ thể là rất quan trọng để có được kết quả nhanh và chính xác.

  • match: Được sử dụng cho full-text search (tìm kiếm toàn văn bản). Elasticsearch sẽ phân tích chuỗi đầu vào và so khớp nó với các token đã được lập chỉ mục.
  • multi_match: Tương tự như match, nhưng cho phép tìm kiếm qua nhiều trường cùng lúc. Điều này hữu ích khi bạn muốn tìm kiếm một từ khóa trong nhiều thuộc tính khác nhau của tài liệu.
  • bool query: Dùng để kết hợp các truy vấn khác nhau bằng các toán tử logic (như must, should, must_not, filter). bool cho phép bạn tạo các truy vấn phức tạp, bao gồm nhiều điều kiện.
  • Boosting là kỹ thuật để tăng hoặc giảm tầm quan trọng của một số trường hoặc kết quả trong quá trình tính điểm relevance score.

Áp dụng filters thay vì queries khi có thể:

Trong Elasticsearch, filters và queries có những cách hoạt động khác nhau. Filters không tính relevance score (điểm liên quan) cho các tài liệu, trong khi queries thường tính toán độ phù hợp giữa truy vấn và tài liệu để sắp xếp kết quả. Điều này có nghĩa là các filters sẽ nhanh hơn trong nhiều trường hợp.

Khi sử dụng filter, Elasticsearch có thể lưu trữ (cache) kết quả của filter đó. Nếu bạn chạy lại cùng một truy vấn hoặc một filter tương tự, Elasticsearch sẽ dùng lại kết quả từ cache thay vì phải tính toán lại từ đầu, điều này làm tăng hiệu suất đáng kể.

Tối ưu hóa full-text search:

  • Cấu hình analyzers phù hợp cho từng trường. Ví dụ: đối với trường tên sản phẩm, cần một analyzer để loại bỏ ký tự đặc biệt và chuyển văn bản thành chữ thường.
  • synonyms (từ đồng nghĩa): ví dụ như "xe máy" và "honda"
  • stopwords (từ vựng): ví dụ những từ phổ biến như "và", "hoặc", "nhưng" thường không mang nhiều ý nghĩa khi tìm kiếm thì nên vứt ra.
  • fuzzy search: giúp tìm kiếm các từ gần đúng với từ khóa người dùng nhập vào. Ví dụ người dùng nhập sai từ lợn thành loz thì vẫn ra được.
  • ngram tokenizers là một kỹ thuật chia nhỏ từ thành các mẩu nhỏ hơn. Ví dụ: Từ "search" có thể được chia thành các ngram như: se, ear, arc, rch
  • Aggregations cho phép thực hiện các phép tính và phân tích dữ liệu trực tiếp trong truy vấn tìm kiếm. Điều này rất hữu ích để tạo các insights phức tạp từ dữ liệu.
    • Bucket aggregations giúp phân nhóm dữ liệu thành các nhóm (buckets) dựa trên các điều kiện nhất định. Ví dụ phân loại theo "price range"
    • Metric aggregations thực hiện các phép tính thống kê như tính tổng, trung bình, cực đại, cực tiểu, hoặc đếm (count) trên một tập hợp dữ liệu. Ví dụ: tính tổng doanh số hoặc số lượng sản phẩm trong từng nhóm đã được phân chia bởi bucket aggregation.
    • Hoặc kết hợp nhiều loại aggregations để tạo ra insights phức tạp hơn.

Caching và Performance Tuning

  • Cấu hình query cache:
    • Bật query cache cho các truy vấn thường xuyên được sử dụng
    • Điều chỉnh kích thước cache phù hợp với bộ nhớ có sẵn
    • Sử dụng request cache cho các truy vấn search và aggregation
  • Sử dụng field data cache:
    • Cấu hình field data cache cho các trường thường xuyên được sử dụng trong sorting và aggregations
    • Giới hạn kích thước field data cache để tránh OOM errors
  • Tối ưu hóa JVM settings:
    • Điều chỉnh heap size phù hợp (không quá 50% RAM vật lý)
    • Cấu hình garbage collection để giảm thiểu latency
    • Sử dụng G1GC cho các cluster lớn

5. Scale up

Có một vài điểm lúc mới tìm hiểu về ES mình confuse nhẹ, tại trước đó mình học mongodb nên thấy khái niệm của ES vừa giống mà lại vừa khác đó là:

  • Trong MongoDB, một shard thường là một replica set độc lập, có thể chứa nhiều nodes.
  • Trong Elasticsearch, một node có thể chứa nhiều shards, và mỗi shard là một phần của một index.

Về phần scale up thì có một số điểm cần lưu ý như sau:

Cấu hình số lượng shards và replicas tối ưu:

  • Tính toán số lượng shards dựa trên kích thước dữ liệu và hardware: Quy tắc chung là mỗi shard nên có kích thước hợp lý để tránh quá tải cho một shard cụ thể. Kích thước shard lý tưởng phụ thuộc vào yêu cầu hiệu suất của ứng dụng, nhưng thường thì từ 10GB đến 50GB là phù hợp cho một shard.
  • Cân bằng giữa hiệu suất và tính sẵn sàng khi cấu hình replicas: Số lượng replicas ảnh hưởng đến hiệu suất và tính sẵn sàng. Càng nhiều replicas, hệ thống sẽ có khả năng phục hồi nhanh khi có sự cố và tăng khả năng xử lý các yêu cầu đọc. Thường thì mình làm 3 con 1 write, 2 read.
  • Sử dụng forced awareness để đảm bảo high availability: tính năng giúp Elasticsearch biết về zone hoặc availability domain trong một môi trường nhiều máy chủ (cluster). đảm bảo rằng các shard chính (primary shard) và bản sao (replica) không nằm trên cùng một zone, giúp đảm bảo hệ thống hoạt động dù 1 zone nào đó bị lỗi.

Chiến lược sharding phù hợp:

Mặc định, Elasticsearch phân phối dữ liệu đến các shard một cách ngẫu nhiên, nhưng bạn có thể sử dụng custom routing để kiểm soát chi tiết hơn việc phân phối dữ liệu.

Ví dụ: Nếu bạn có các bộ dữ liệu lớn liên quan đến một khách hàng cụ thể và muốn giữ chúng trong cùng một shard để tối ưu hóa tìm kiếm, bạn có thể sử dụng custom routing bằng cách đặt routing key là customer_id.

Bình luận

Bài viết tương tự

- vừa được xem lúc

RESTful API Design: Best Practices

Hey hey hey hey, cuối năm cũng khá bận bịu công việc này kia nên cũng không có nhiều thời gian viết bài phục vụ anh em được. Nay mình xin chia sẻ một vài những tiêu chí mà mình hay sử dụng khi viết REST API.

0 0 37

- vừa được xem lúc

18. Responsive là gì?

Truy cập http://fullstack.edu.

0 0 42

- vừa được xem lúc

19. Media queries?

Truy cập http://fullstack.edu.

0 0 42

- vừa được xem lúc

20. Tablet responsive

Truy cập http://fullstack.edu.

0 0 33

- vừa được xem lúc

21. Mobile menu responsive

Truy cập http://fullstack.edu.

0 0 32

- vừa được xem lúc

22. Mobile menu fix bug

Truy cập http://fullstack.edu.

0 0 25