หลังจากที่หลงทาง พยายามหา algorithm ต่างๆ ในการดึงข้อมูล article ที่คล้ายกับ article ที่เราต้องการเสียหลายวิธี (dismax, tags with boost parameter, aging deboost) ซึ่งก็ได้ผลมาในระดับหนึ่ง ปัญหาที่เกิดก็คือ การปรับแต่ง parameter เพื่อให้ได้ผลที่ต้องการ หรือแม้แต่ตัว query เองมันยากมากกกก
แต่แทบไม่เชื่อตัวเองว่า elasticsearch มี query แบบพิเศษแบบหนึ่ง ที่ช่วยให้โลกน่าอยู่ขึ้นมาก และมีมาตั้งนานแล้ว (ทำไมเมื่อก่อนไม่เจอ) นั่นก็คือ MLT – More Like This query นั่นเอง (link เป็น doc ตัว 7.3 แต่ลองเอา query ไปรันใน 2.x ก็ทำงานได้ปกติ)
syntax ของมันก็ง่ายมาก โดยเบื้องต้นเราสามารถตั้ง reference ตั้งต้นได้ 2 วิธี คือ จากตัว doc หรือจากค่าที่ต้องการ
อ้างอิงตัวอย่างจากใน reference URL ด้านบนนะครับ แต่จะอธิบายรายละเอียดเพิ่มดังนี้
เลือก query result จาก search term ที่ต้องการ
GET /_search { "query": { "more_like_this" : { "fields" : ["title", "description"], "like" : "Once upon a time", "min_term_freq" : 1, "max_query_terms" : 12 } } }
query -> more_like_this การระบุประเภทของ query เป็นแบบ MLT
fields ระบุฟิลด์ที่จะนำไปค้นหา term (คำค้น)
like term ที่เราจะค้นหา (ถูกนำไป process ก่อนค้นหาตามปกติ)
min_term_freq จำนวนขั้นต่ำของ term ที่จะปรากฏในผลการค้นหา (default = 2)
max_query_terms จำนวน term สูงสุดที่จะนำไปหาความคล้ายคลึง (ยิ่งเยอะยิ่งตรง แต่จะกิน resource มากขึ้นเช่นกัน)
เลือก query result จาก reference doc
GET /_search { "query": { "more_like_this" : { "fields" : ["title", "description"], "like" : [ { "_index" : "imdb", "_id" : "1" }, { "_index" : "imdb", "_id" : "2" }, "and potentially some more text here as well" ], "min_term_freq" : 1, "max_query_terms" : 12 } } }
เคสนี้เราจะใช้ reference doc ได้เลย โดยระบุด้วย index, type และ id และยังเลือกฟิลด์ที่จะต้องการเทียบความคล้ายได้ด้วย
ตัวอย่างค่อนข้าง advanced คือมี doc ที่ใช้เทียบมากกว่า 1 doc และแถมด้วยการระบุ custom term ไปด้วย
ใช้ MLT query ร่วมกับ filter และการ boost
ตัวอย่างด้านล่างนี้ (PHP) เป็นการระบุ filter ด้วยฟิลด์ publishTime เพื่อป้องกันไม่ให้ result มี doc ที่เก่ากว่าที่กำหนดมา นอกจากนั้นยังมีการระบุ boost parameter ให้กับฟิลด์ tags มากกว่า title และ abstract
$query = [ 'query' => [ 'bool' => [ 'must' => [ 'dis_max' => [ 'queries' => [ 'more_like_this' => [ 'fields' => ['tags'], 'like' => [ [ '_index' => 'myindex', '_type' => 'article', '_id' => (string)$id, ] ], 'min_term_freq' => 1, 'max_query_terms' => 10, 'boost' => 4, ], 'more_like_this' => [ 'fields' => ['title', 'abstract'], 'like' => [ [ '_index' => 'myindex', '_type' => 'article', '_id' => (string)$id, ] ], 'min_term_freq' => 1, 'max_query_terms' => 20, 'boost' => 2, ] ] ] ], 'filter' => [ 'range' => [ 'publishTime' => [ 'gt' => date('Y-m-d H:i:s', strtotime("-$maxAge days")), ] ] ] ] ], 'size' => $limit ];
จะเห็นว่า MLT query ช่วยให้โครงสร้างและการคำนวณความเกี่ยวข้องของ article นั้นเข้าใจง่ายขึ้นมาก และยังสามารถปรับแต่ง score / filter ได้ด้วย จากการทดสอบพบว่า ได้ผลลัพธ์ที่น่าพอใจ และ query ทำงานได้รวดเร็ว