การค้นหาแบบ Elasticsearch Typeahead 101

Engineering & Tech Blog
FLOWACCOUNT TECH BLOG
2 min readMar 15, 2022

สวัสดีครับ กลับมาพบกันอีกครั้งกับ 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

--

--

Engineering & Tech Blog
FLOWACCOUNT TECH BLOG

FlowAccount is Thailand’s leading online accounting software with over 90+ employees and backed by global investors which includes Sequoia Capital