การค้นหาแบบ Elasticsearch Typeahead 101
สวัสดีครับ กลับมาพบกันอีกครั้งกับ FlowAccount Tech Blog บล็อกความรู้สายเทคที่อ่านง่ายเข้าใจง่ายใน 5 นาที‼️
บทที่แล้วเป็นยังไงบ้างครับสำหรับการค้นหาและการจัดเรียงสำหรับเว็บแอปพลิเคชั่น (Generic Searching and Sorting) 😄😄 ไม่ยากเลยใช่ไหมครับ
วันนี้เราจะมาพูดถึงวิธีการทำตัวช่วยค้นหาในช่องค้นหา หรือเรียกว่า Elasticsearch Typeahead (Auto-complete) 101 แบบฉบับภาษาไทย
ในรูปแบบการพัฒนาแบบลีน เราไม่ได้คำนึงถึงการเติบโตของผลิตภัณฑ์ แต่เราคำนึงถึงการใช้งานหลักก่อนเสมอ แต่เมื่อหลายสิ่งหลายอย่างเข้าที่เข้าทางเป็นไปได้ด้วยดี มีผู้ใช้งานเยอะขึ้น ปัญหาเริ่มถาโถมตามเข้ามา 😅 ฉะนั้นเราไม่สามารถมองข้าม หรือแก้ปัญหาเฉพาะหน้าเวลาจัดการปัญหาทาง technical ต่างๆ ได้
เกริ่นมาเยอะแล้ว มาเริ่มกันดีกว่า!
เมื่อเราเริ่มต้น Startup ครั้งแรก เราจะยังไม่ค่อยมีทักษะในการพัฒนาผลิตภัณฑ์ให้พร้อมใช้งานในวงกว้างมากนัก และมักจะลงเอยด้วยการแก้ไขแบบลวกๆ โดยไม่ได้คำนึงถึงประสิทธิภาพของโค้ดและโครงสร้างพื้นฐานของทั้งระบบ มีคนเคยบอกว่า “เราต้องมี โคตรทักษะความคิด-ตรรกะแบบเซียนหมากรุก ในการวางแผนงานที่เหมาะสม เพื่อให้บรรลุเป้าหมายโค้ด/โครงสร้างพื้นฐานที่ scalable ให้ได้กว่า 80% ของโค้ดทั้งหมด”
การเริ่ม Startup ครั้งแรกเป็นเรื่องที่ยากและหินเสมอ ไม่ต้องหันไปถามใคร ดูผู้เขียนบทความนี้ได้ ผมเคยผ่านจุดนั้นมาก่อน ไม่รู้ว่าจะยากไปไหน! 😌
ปัญหาที่พบได้ทั่วไป คือ คืออ คือออ… เริ่มจากการที่ฐานข้อมูลของเราเริ่มรับไม่อยู่แล้วพร้อมจะระเบิด 💣 …เราเลยต้องเริ่มหาวิธีแก้ไข ณ เวลานั้น ไม่มีใครช่วยได้จริงๆ จังๆ ยกเว้น Google และคำมหัศจรรย์ที่เรียกว่า “Caching” ซึ่งสมัยก่อนผู้ใช้ส่วนมากเริ่มบ่นและไม่สนใจที่จะใช้ 🤭ในขณะที่เราทำการวิจัย ค้นคว้า และการพัฒนาเพื่อหาวิธีแก้ปัญหาที่ยั่งยืน!
แล้วเราต้องทำอย่างไรล่ะ
เราต่างเริ่มใช้ Google และพยายามปรับแต่งโค้ดอื่นๆ ทั้งหมด โดยหวังว่าจะให้ผ่านพ้นไปวันๆ จนในที่สุด เราถึงได้รู้ว่าโครงสร้างพื้นฐานของ Caching&Searching เป็นสิ่งที่ดีมากๆ ทำให้เราประหยัดเวลาได้ ในการที่ระบบจดจำข้อมูลเก่าไว้แล้วนำมาใช้ครั้งหน้าได้ เราเริ่มตระหนักถึงความจำเป็นที่ต้องนำ Caching&Searching กลับคืนมา
แต่…สมัยก่อนมันยังไม่มีเสิร์ชเอ็นจิ้น (Search Engine) แล้วเราก็ไม่เคยคิดถึงมันก่อนหน้านี้ ฉะนั้นเราเลยสับสนกับบทความ ข้อมูลต่างๆ ใน Google ที่เวลาเราค้นหาแล้วก็เจอข้อมูลที่ตรงและไม่ตรงบ้าง จนไม่รู้จะเริ่มตรงไหน ใครเป็นบ้างยกมือขึ้น!
การสร้าง Index พื้นฐาน
อาจจะเคยได้ยินว่า มีการทำ Token Filters (Tokenizers) ซึ่งเราเข้าใจกันผิด เพื่อการใช้ Ngram Filter + Standard Tokenizer ในการทำ index พื้นฐาน ลองคิดว่าเหมือนการ Like %{xx}% นั่นเอง ซึ่งเมื่อผู้ใช้ค้นหาด้วยคำต่างๆ ของตนก็จะได้รับช่องว่างหรือคำปรากฏขึ้นแล้วหายไปหลังจากอักขระถัดไปที่ผู้ใช้พิมพ์
ยกตัวอย่างคำว่า น้ำเฉาก๊วย เมื่อค้นหา เราก็ได้ผลลัพธ์แบบนี้
"my_first_tokenizer": {
"type": "ngram",
"min_gram": 1,
"max_gram": 10,
"token_chars": [
"letter",
"digit",
"whitespace"
]
}"น้ำเ" ==> "น้ำเฉาก๊วย"
"น้ำเฉ" ==> ""
"น้ำเฉา" ==> ""
"น้ำเฉาก" ==> "น้ำเฉาก๊วย"
คุยกันยืดยาวมาก ตอนนี้เดินทางมาจนใกล้เสร็จสักที
ก่อนหน้านี้ ผมยังเป็นเด็กอ่อนหัด แต่หลังจากนอนไม่หลับสองสามคืน และคิดแต่ Kibana query … จนได้วิธีการแก้ปัญหา ซึ่งก็คือ
“การตั้งค่า The Setting” นั่นเอง❗️
โดยพื้นฐานแล้ว ผมพบว่าสามารถเขียน elasticsearch ได้หลายล้านวิธี และมันขึ้นอยู่กับว่าคุณใช้มันอย่างไรเพื่อให้บรรลุเป้าหมายของคุณ! มีตัวการให้คำค้นหาแบบ “suggest” แต่ก็ยังมีปัญหาในการกำหนดค่า และโดยส่วนตัวแล้ว ผมไม่พบวิธีให้ Contain query ทำงานในแบบที่เราต้องการ ให้มีการค้นหาคำในวลี/คำ
ดังนั้นผมจึงเขียนแบบนี้แทน
"analysis": {
"filter": {
"autocomplete_filter": {
"type": "edge_ngram",
"min_gram": 1,
"max_gram": 255,
"side": "front"
}
},
"analyzer": {
"autocomplete": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"autocomplete_filter"
]
}
"autocomplete_thai": {
"type": "custom",
"tokenizer": "icu_tokenizer",
"filter": [
"lowercase",
"autocomplete_filter"
]
}
}
}
},
"mappings": {
"productesmodel": {
"properties": {
"name": {
"type": "text",
"analyzer": "autocomplete",
"search_analyzer": "standard",
"fields": {
"keyword": {
"type": "keyword",
"doc_values": true,
"normalizer": "lowercase_normalizer"
}
}
},
"nameth": {
"type": "text",
"analyzer": "autocomplete_thai",
"search_analyzer": "standard",
"fields": {
"keyword": {
"type": "keyword",
"doc_values": true,
"normalizer": "lowercase_normalizer"
}
}
}
}
}
}
The Query
ต่อมากำหนดฟิลด์ ‘fields” ที่มี Tokenizers ต่างกัน หนึ่งคือ icu_tokenizer และ edge_gram เราสามารถทำการเติมข้อความอัตโนมัติได้ทันทีเลย อย่างไรก็ตาม การค้นหาต้องค้นหาผ่านสองฟิลด์ มิฉะนั้น อักขระที่เชื่อมต่อกันจะไม่ return ผลการค้นหาใดๆ เช่นเดียวกับด้านล่าง ถ้าผมลบฟิลด์ “name” จะไม่มีผลลัพธ์ใดๆ เนื่องจาก icu_tokenizer นั้นมีสองคำในฟิลด์ “name_th”
POST /index/productesmodel/_search
{
"query" : {
"multi_match" : {
"query": "น้ำเ",
"type": "phrase",
"fields": ["nameth","name"]
}
}
}
และแล้วก็เดินทางมาถึงบทสรุปกันแล้วครับ 😊
มีหลายล้านวิธีที่คุณสามารถทำ Elasticsearch Engine ได้ นี่เป็นเพียงส่วนเล็กๆ เท่านั้น หวังว่าคุณจะสนุกกับการอ่านและลองทำ ลองผิดลองถูก เพราะ “The new power is data” ขั้นตอนต่อไปคือ การใช้ “score” และ “weights” ในการเล่นกับการค้นหาและคำแนะนำ เพื่อแสดงการจับคู่ที่เกี่ยวข้องมากขึ้น!
หากใครมีคำแนะนำหรือวิธีเจ๋งๆ สามารถมาแชร์กันได้นะครับ รอคำตอบคูลๆ ของทุกคนนะครับ 😊
หากชอบบทความของ FlowAccount Tech Blog อย่าลืมกด Follow นะครับ ติดตามบทความอื่นจาก FlowAccount Tech Blog ได้ที่ https://medium.com/flowaccount-tech
Open Positions jobs available on FlowAccount > https://flowaccount.com/en/jobs