12/08/2018, 11:08

Tối ưu hóa kết quả tìm kiếm trong ElasticSearch với scoring và booting

Mặc dù ElasticSearch cung cấp cho chúng ta một thuật toán scoring hiểu quả, tuy nhiên trong một số trường hợp điều đó là chưa đủ. Ví dụ như hệ thống thương mại điện tử, nhiều người dùng có xu hướng chỉ quan tâm tới những kết quả trên cùng. Điều này có ý nghĩa thực sự quan trọng để chúng ta có một ...

Mặc dù ElasticSearch cung cấp cho chúng ta một thuật toán scoring hiểu quả, tuy nhiên trong một số trường hợp điều đó là chưa đủ. Ví dụ như hệ thống thương mại điện tử, nhiều người dùng có xu hướng chỉ quan tâm tới những kết quả trên cùng. Điều này có ý nghĩa thực sự quan trọng để chúng ta có một scoring linh hoạt. Nếu như chúng ta tạo ra những kết quả trên cùng đúng với mong muốn của người sử dụng thì tỷ lệ chuyển đổi của bạn chắc chắn sẽ tăng đáng kể. Elasticsearch.jpg Trong bài viết này chúng ta sẽ tìm hiểu về scoring trong ElasticSearch và bên cạnh đó cũng tìm hiểu về việc tinh chỉnh scoring. Điều này giúp chúng ta thực hiện được tối ưu hóa danh sách kết quả tìm kiếm phù hợp với nhu cầu người sử dụng.

Mặc định, ElasticSearch sử dụng công thức tính scoring của Lucense, đại diện cho mối liên hệ giữa mỗi document với một điểm số được biết tới là _score. _score càng cao thì mức độ liên quan tới document càng nhiều. Mỗi một mệnh đề query tạo ra một _score cho mỗi document, và được tính toán điểm số phụ thuộc vào loại mệnh đề truy vấn.

Mệnh đề truy vấn phục vụ các mục đích khác nhau: một truy vấn không rõ ràng có thể xác định _score bằng cách tính toán sự tương tự nhau như thế nào của các từ trong search term ban đầu; một truy vấn sẽ kết hợp với phần trăm những điều kiện đã được tìm thấy. Tuy nhiên, ý nghĩa chung của sự liên quan là thuật toán cho phép tính toán sự tương đồng của những nội dung lưu trữ và chuỗi truy vấn.

Về cơ bản thuật toán được sử dụng trong ElasticSearch được biết tới như là term frequency/inverse document frequency (gọi tắt là tf/idf) và nó có các yếu tố sau:

factor desciption
tf term frequency
idf inverse document frequency
coord measure of matching on multiple terms
lengthnorm measure of matching on smaller fields
querynorm query normalization factor
boost(index) boost factor at indexing time
boost(query) boost factor at query time

Bảng trên là danh sách các yếu tố xác định score của một document trong ElasticSearch.

Term Frequency (tf) là phép đo số lần xuất hiện của một từ trong một document trong một bối cảnh nào đó. Nếu số lần xuất hiện càng cao thì score sẽ càng cao và tỉ lệ xuất hiện của document cũng sẽ cao.

Inverse Document Frequency (idf) là phép đo tần xuất của các từ khóa tìm kiếm xuất hiện trên một tập document. Thông thường, nếu từ khóa tìm kiếm xuất hiện trên nhiều documents thì score sẽ thấp. Trường hợp ít xuất hiện cũng là nguyên nhân dẫn tới tăng giá trị của score.

Coord là phép đo sự trùng khớp trên nhiều điều kiện tìm kiếm, và giá trị càng cao trên một phép đo thì sẽ làm tăng giá tổng thế score. Xem xét một tìm kiếm với 2 từ "woolen" và "jacket". Không quan trọng việc bạn chạy từng truy vấn: nó sẽ chạy bên trong giống như một bool truy vấn và những tìm kiếm riêng biệt sẽ chạy trên mỗi từ khóa. Một document có cả 2 sẽ có điểm số cao hơn những document chỉ có 1 hoặc không. Nếu bạn thực hiện truy vấn đồng thời cả 2 thì mỗi document chứ cả 2 từ khóa sẽ có một cooord 2*2 = 4. Tuy nhiên, một document chỉ chứa 1 trong các từ khóa sẽ có coord là 2*1 = 2.

lengthnorm là phép đo trên những field nhỏ và tạo ra giá trị lớn. Ví dụ: nếu từ khóa tìm kiếm phù hợp ở một trường title thay vì content.

Mặc dù không trực tiếp tác động trực tiếp tới document, một querynorm là một phép so sánh giữa các truy vấn khi sử dụng kết hợp các loại truy vấn.

Score cũng có thể bị ảnh hưởng bởi các yếu tố: index time boost và query time boost. Boosting là một trường đặc biệt, là yếu tốt có ý nghĩa quan trọng trong việc tính toán score.

Công thức tính score

score(q,d) = queryNorm(q) * coord(q,d) * ∑ (tf(t in d) * idf(t)² * t.getBoost() * norm(t,d)) (t in q)

Thực sự là tôi cũng muốn xem cách sử dụng tất các những thành phần của công thức trên hoạt động như thế nào cho việc tính toán score của một document. Nhưng trước hết, một điều quan trọng chúng ta cần phải biết là công cụ debug score cho những truy vấn của ElasticSearch. Nếu muốn giải thích cho một truy vấn, chúng ta sẽ có thông tin chi tiết điểm số của các thành phần trong công thức trên cùng với score cuối cùng của một document. Tất nhiên là chúng ta không nên sử dụng nó cho môi trường production, và chỉ nên dùng trong môi trường develop mà thôi.

Công cụ tốt nhất để kiểm tra _score của một truy vấn là function_score.

ElasticSearch thực tế cung cấp nhiều phương pháp để tính toán score cho mỗi query. Chúng ta có thể sử dụng truy vấn custom_score cùng với một script để truy cập giá trị của từng trường số riêng biệt. Script có dạng như sau:

"script" : "_score * doc['my_numeric_field'].value"

Truy vấn function_score cung cấp cho chúng ta khả năng định nghĩa những function tính toán score. Ngoài việc tạo ra các functions, chúng ta có thể tạo ra một scipt với nhiều function hơn nữa. Với function_score, chúng ta cần định nghĩa một query và các tùy chọn cho bộ lọc, giúp giảm đáng kể việc tính toán không mong muốn. Nếu chúng ta đã chọn cơ chết boost, chúng ta có thể quyết định những gì chúng ta muốn làm với kết quả từ custom_function chúng ta tạo ra với điểm số của nó. Chúng ta hoàn toàn có thể thay thế score bằng score mặc định, hoặc là nhân score mặc định với score đã được tính toán.

ElasticSearch cũng cho phép chúng ta sử dụng nhiều function để tính toán một score là sự kết hợp nhiều kết quả từ những function. Ngoài ra còn có nhiều cách để sử dụng function_score áp dụng vào các yếu tố khác như: recency, khoảng cách từ một điểm đặc biệt và độ phổ biến. Chúng ta sẽ tìm hiểu sâu hơn về những tùy chọn để điều chỉnh sự liên quan tới một tập dữ liệu.

script_score giúp chúng ta định nghĩa một scoring function trong một kịch bản. Với field_value_factor, chúng ta có thể truy vấn một trường cụ thể vì thế nó có thể đóng góp trực tiếp tới việc tính toán final score. DECAY_FUNCTION sẽ cung cấp cho chúng ta score trong terms của một decaying mode.

Xem xét một ví dụ, chúng ta cần tím kiếm địa điểm và chúng ta mong muốn giá trị score của những địa điểm có khoảng cách bé hơn 5km sẽ gấp 3 lần những địa điểm lớn hơn 5km so với vị trí mốc. Hoặc một ví dụ khác, chúng ta tìm kiếm các tài liệu liên quan tới ngày xuất bản, và chúng ta muốn những tài liệu xuất bản trong vòng 15 ngày sẽ có score là 7, trong 25 ngày tiếp theo là 3, .... Trong trường hợp này, chúng ta có thể sử dụng DECAY_FUNCTION cũng như weight function và random function. Tất nhiên, chúng ta cần viết một custom function để áp dụng những thay đổi trên những function này.

Như chúng ta đã đề cập ở trên, chúng ta có thể sử dụng nhiều function để tính toàn score, và sau đó sử dụng score_mode và boost_mode để kết hợp output của những function đó. score_mode định nghĩa các score từ những function riêng sẽ kết hợp, boot_mode định nghĩa cách chúng ta áp dụng các giá trị kết quả của những function cụ thể để mặc định hay thêm vào hay nhân với tổng của tất cả các kết quả của các function. Bảng dưới là danh sách các tùy chọn boost_mode và score_mode:

boost_mode

multiply multiply the query score and function score (this is the default)
sum add the query score to the function score
avg average the query score and custom score
first replace the query score with the function score
min take the smallest of the query score and function score
max take the largest of the query score and function score

score_mode

multiply multiply the function scores (this is the default)
sum add the function scores
avg average the function scores
first apply the first function score that has a matching filter
min take the smallest of the function scores
max take the largest of the function scores

Bây giờ chúng ta xem xét một ví dụ thực tế. Thay vì sử dụng giá trị mặc định, chúng ta xem xét và tùy chỉnh để lấy các giá trị phổ biến dựa vào rating. Cách đơn giản là chúng ta sẽ định nghĩa một function_score và sử dụng field_value_factor để truy cập tới rating value.

POST /ecomercedata/gadgets/_search
{
   "explain": true,
   "query": {
      "function_score": {
        "query": {
            "match_all": {}
         },
         "functions": [
                        {
               "field_value_factor": {
                  "field": "rating"
               }
            }
         ],
                  "boost_mode": "multiply"
      }
   }
}

Kết quả nhận được là:

{{   "took": 22,
   "timed_out": false,
   "_shards": {
      "total": 1,
      "successful": 1,
      "failed": 0
   },
   "hits": {
      "total": 9,
      "max_score": 9,
      "hits": [
         {
            "_shard": 0,
            "_node": "477kWUQVR2eiLpIQEN4vFw",
            "_index": "ecomercedata",
            "_type": "gadgets",
            "_id": "nKk9DfRnTDyUU80cepXRrw",
            "_score": 9,
            "_source": {
               "name": "MacBookPro",
               "category": "Laptop",
               "brand": "Apple",
               "rating": 9,
               "prize": 1299,
               "piecesSold": 9500,
               "dateOfRelease": "2005-02-01"
            },
            "_explanation": {
               "value": 9,
               "description": "function score, product of:",
               "details": [
                  {
                     "value": 1,
                     "description": "ConstantScore(*:*), product of:",
                     "details": [
                        {
                           "value": 1,
                           "description": "boost"
                        },
                        {
                           "value": 1,
                           "description": "queryNorm"
                        }
                     ]
                  },
                  {
                     "value": 9,
                     "description": "Math.min of",
                     "details": [
                        {
                           "value": 9,
                           "description": "function score, score mode [multiply]",
                           "details": [
                              {
                                 "value": 9,
                                 "description": "function score, product of:",
                                 "details": [
                                    {
                                       "value": 1,
                                       "description": "match filter: *:*"
                                    },
                                    {
                                       "value": 9,
                                       "description": "field value function: (doc['rating'].value * factor=1.0)",
                                       "details": [
                                          {
                                             "value": 1,
                                             "description": "ConstantScore(*:*), product of:",
                                             "details": [
                                                {
                                                   "value": 1,
                                                   "description": "boost"
                                                },
                                                {
                                                   "value": 1,
                                                   "description": "queryNorm"
                                                }
                                             ]
                                          }
                                       ]
                                    }
                                 ]
                              }
                           ]
                        },
                        {
                           "value": 3.4028235e+38,
                           "description": "maxBoost"
                        }
                     ]
                  },
                  {
                     "value": 1,
                     "description": "queryBoost"
                  }
               ]
            }
         },
         {
            "_shard": 0,
            "_node": "477kWUQVR2eiLpIQEN4vFw",
            "_index": "ecomercedata",
            "_type": "gadgets",
            "_id": "KNycQwC5TcSmhXPBdKgW3g",
            "_score": 9,
            "_source": {
               "name": "Ipad",
               "category": "Tablet",
               "brand": "Apple",
               "rating": 9,
               "prize": 600,
               "piecesSold": 9500,
               "dateOfRelease": "2005-07-01"
            },
            "_explanation": {
               "value": 9,
               "description": "function score, product of:",
               "details": [
                  {
                     "value": 1,
                     "description": "ConstantScore(*:*), product of:",
                     "details": [
                        {
                           "value": 1,
                           "description": "boost"
                        },
                        {
                           "value": 1,
                           "description": "queryNorm"
                        }
                     ]
                  },
                  {
                     "value": 9,
                     "description": "Math.min of",
                     "details": [
                        {
                           "value": 9,
                           "description": "function score, score mode [multiply]",
                           "details": [
                              {
                                 "value": 9,
                                 "description": "function score, product of:",
                                 "details": [
                                    {
                                       "value": 1,
                                       "description": "match filter: *:*"
                                    },
                                    {
                                       "value": 9,
                                       "description": "field value function: (doc['rating'].value * factor=1.0)",
                                       "details": [
                                          {
                                             "value": 1,
                                             "description": "ConstantScore(*:*), product of:",
                                             "details": [
                                                {
                                                   "value": 1,
                                                   "description": "boost"
                                                },
                                                {
                                                   "value": 1,
                                                   "description": "queryNorm"
                                                }
                                             ]
                                          }
                                       ]
                                    }
                                 ]
                              }
                           ]
                        },
                        {
                           "value": 3.4028235e+38,
                           "description": "maxBoost"
                        }
                     ]
                  },
                  {
                     "value": 1,
                     "description": "queryBoost"
                  }
               ]
            }
         },
         {
            "_shard": 0,
            "_node": "477kWUQVR2eiLpIQEN4vFw",
            "_index": "ecomercedata",
            "_type": "gadgets",
            "_id": "IfTr4n90Tbez-t26Iu6JCg",
            "_score": 8,
            "_source": {
               "name": "MacBookAir",
               "category": "Laptop",
               "brand": "Apple",
               "rating": 8,
               "prize": 1099,
               "piecesSold": 8700,
               "dateOfRelease": "2006-05-01"
            },
            "_explanation": {
               "value": 8,
               "description": "function score, product of:",
               "details": [
                  {
                     "value": 1,
                     "description": "ConstantScore(*:*), product of:",
                     "details": [
                        {
                           "value": 1,
                           "description": "boost"
                        },
                        {
                           "value": 1,
                           "description": "queryNorm"
                        }
                     ]
                  },
                  {
                     "value": 8,
                     "description": "Math.min of",
                     "details": [
                        {
                           "value": 8,
                           "description": "function score, score mode [multiply]",
                           "details": [
                              {
                                 "value": 8,
                                 "description": "function score, product of:",
                                 "details": [
                                    {
                                       "value": 1,
                                       "description": "match filter: *:*"
                                    },
                                    {
                                       "value": 8,
                                       "description": "field value function: (doc['rating'].value * factor=1.0)",
                                       "details": [
                                          {
                                             "value": 1,
                                             "description": "ConstantScore(*:*), product of:",
                                             "details": [
                                                {
                                                   "value": 1,
                                                   "description": "boost"
                                                },
                                                {
                                                   "value": 1,
                                                   "description": "queryNorm"
                                                }
                                             ]
                                          }
                                       ]
                                    }
                                 ]
                              }
                           ]
                        },
                        {
                           "value": 3.4028235e+38,
                           "description": "maxBoost"
                        }
                     ]
                  },
                  {
                     "value": 1,
                     "description": "queryBoost"
                  }
               ]
            }
         },
         {
            "_shard": 0,
            "_node": "477kWUQVR2eiLpIQEN4vFw",
            "_index": "ecomercedata",
            "_type": "gadgets",
            "_id": "90hw7WyKSu2X0YAk3NBTMQ",
            "_score": 8,
            "_source": {
               "name": "ATIVBook",
               "category": "Laptop",
               "brand": "Samsung",
               "rating": 8,
               "prize": 1899,
               "piecesSold": 3500,
               "dateOfRelease": "2014-05-01"
            },
            "_explanation": {
               "value": 8,
               "description": "function score, product of:",
               "details": [
                  {
                     "value": 1,
                     "description": "ConstantScore(*:*), product of:",
                     "details": [
                        {
                           "value": 1,
                           "description": "boost"
                        },
                        {
                           "value": 1,
                           "description": "queryNorm"
                        }
                     ]
                  },
                  {
                     "value": 8,
                     "description": "Math.min of",
                     "details": [
                        {
                           "value": 8,
                           "description": "function score, score mode [multiply]",
                           "details": [
                              {
                                 "value": 8,
                                 "description": "function score, product of:",
                                 "details": [
                                    {
                                       "value": 1,
                                       "description": "match filter: *:*"
                                    },
                                    {
                                       "value": 8,
                                       "description": "field value function: (doc['rating'].value * factor=1.0)",
                                       "details": [
                                          {
                                             "value": 1,
                                             "description": "ConstantScore(*:*), product of:",
                                             "details": [
                                                {
                                                   "value": 1,
                                                   "description": "boost"
                                                },
                                                {
                                                   "value": 1,
                                                   "description": "queryNorm"
                                                }
                                             ]
                                          }
                                       ]
                                    }
                                 ]
                              }
                           ]
                        },
                        {
                           "value": 3.4028235e+38,
                           "description": "maxBoost"
                        }
                     ]
                  },
                  {
                     "value": 1,
                     "description": "queryBoost"
                  }
               ]
            }
         },
         {
            "_shard": 0,
            "_node": "477kWUQVR2eiLpIQEN4vFw",
            "_index": "ecomercedata",
            "_type": "gadgets",
            "_id": "xquXInoJSSOnPwuzrOTO8A",
            "_score": 8,
            "_source": {
               "name": "GalaxyTab",
               "category": "Tablet",
               "brand": "Samsung",
               "rating": 8,
               "prize": 550,
               "piecesSold": 8500,
               "dateOfRelease": "2007-07-01"
            },
            "_explanation": {
               "value": 8,
               "description": "function score, product of:",
               "details": [
                  {
                     "value": 1,
                     "description": 
            
            
            
         
0