สร้างเสิร์ชเอนจินขั้นสูงด้วย PostgreSQL
(xata.io)- การค้นหาข้อความแบบเต็มของ PostgreSQL เป็นแนวทางในการสร้างฟังก์ชันค้นหาโดยไม่ต้องใช้เสิร์ชเอนจินแยกต่างหาก ด้วยการผสาน
tsvector,tsquery,@@,ts_rankและ GIN index - คำค้นและเอกสารถูกทำให้เป็นมาตรฐานในระดับ lexeme และสามารถแสดงคิวรีด้วยตัวดำเนินการอย่าง AND, OR, NOT, FOLLOWED BY จึงรองรับไวยากรณ์การค้นหาทั่วไปได้เป็นส่วนใหญ่
- ในสภาพแวดล้อมตัวอย่าง GIN index ลดเวลาค้นหาจาก มากกว่า 200ms เหลือประมาณ 4ms แต่เมื่อผลลัพธ์มีจำนวนมากขึ้น ค่าใช้จ่ายในการจัดอันดับและเรียงลำดับของ
ts_rankอาจกลายเป็นคอขวดได้ - การปรับความเกี่ยวข้องทำได้โดยเพิ่มสัญญาณอย่างน้ำหนักของชื่อเรื่อง จำนวนโหวต คะแนน ประเภท และความใหม่ เข้าไปใน นิพจน์การเรียงลำดับ หรือให้น้ำหนักคอลัมน์ด้วย
setweight - สามารถทำการรองรับคำสะกดผิด, faceted search, autocomplete, การค้นหาวลีแบบตรงตัว และ hybrid search ได้เช่นกัน แต่ใน PostgreSQL ต้องเชื่อมองค์ประกอบต่าง ๆ เอง และควรตรวจสอบขีดจำกัดด้านประสิทธิภาพกับชุดข้อมูลขนาดใหญ่
แนวทางของการค้นหาข้อความแบบเต็มใน PostgreSQL
- PostgreSQL มี องค์ประกอบ ระดับล่างสำหรับการค้นหาข้อความแบบเต็ม และสามารถนำมาประกอบกันเพื่อสร้างฟังก์ชันแบบเสิร์ชเอนจินได้
- วิธีนี้ยืดหยุ่น แต่ต้องลงแรงพัฒนามากกว่า Elasticsearch, Typesense และ Meilisearch ซึ่งมีการค้นหาข้อความแบบเต็มเป็นวัตถุประสงค์หลัก
- คิวรีตัวอย่างใช้ชุดข้อมูล Wikipedia Movie Plots จาก Kaggle
- มีชื่อภาพยนตร์ 34,000 เรื่อง
- ขนาดไฟล์รูปแบบ CSV ประมาณ 81MB
องค์ประกอบหลัก
- การค้นหาข้อความแบบเต็มของ PostgreSQL ทำงานโดยมีองค์ประกอบต่อไปนี้เป็นศูนย์กลาง
tsvector: เก็บข้อความเป้าหมายสำหรับค้นหาเป็นรายการ lexeme ที่ทำให้เป็นมาตรฐานแล้วtsquery: แสดงคิวรีค้นหาที่ทำให้เป็นมาตรฐานแล้ว@@: ตัวดำเนินการ match สำหรับตรวจสอบว่าtsqueryตรงกับtsvectorหรือไม่ts_rank,ts_rank_cd: คำนวณคะแนนความเกี่ยวข้องของผลการค้นหา- GIN index: inverted index สำหรับคิวรี
tsvectorอย่างมีประสิทธิภาพ
tsvector และการตั้งค่าการค้นหา
tsvectorเก็บรายการ lexeme ที่เรียงลำดับแล้ว- lexeme คล้ายกับ token แต่เป็นสตริงที่ถูกทำให้เป็นมาตรฐานเพื่อให้รูปแบบต่าง ๆ ของคำเดียวกันถูกรวมเป็นรูปเดียวกัน
- ในการตั้งค่าภาษาอังกฤษ จะทำให้ตัวพิมพ์ใหญ่เป็นตัวพิมพ์เล็กและทำให้เป็นมาตรฐานด้วยการตัด suffix
- เมื่อใช้
to_tsvectorแยกวิเคราะห์ประโยคภาษาอังกฤษ stop words อย่าง “I”, “to”, “an” จะถูกนำออก- “refuse” และ “Refusing” จะถูกแปลงเป็น
refusทั้งคู่ - เครื่องหมายวรรคตอนจะถูกละเว้น
- ตำแหน่งคำในข้อความต้นฉบับและน้ำหนักก็ถูกบันทึกไว้ด้วย
- “refuse” และ “Refusing” จะถูกแปลงเป็น
- หากใช้การตั้งค่า
simpleแทนการตั้งค่าการค้นหาenglishคำจะถูกรวมไว้ตามรูปแบบที่พบในข้อความ- “refuse” และ “refusing” จะยังเป็น lexeme คนละตัว
- การตั้งค่า
simpleมีประโยชน์เป็นพิเศษกับคอลัมน์ที่มี label หรือ tag
- PostgreSQL มีการตั้งค่าการค้นหาในตัวสำหรับหลายภาษา แต่ไม่มีการตั้งค่าสำหรับ CJK (จีน·ญี่ปุ่น·เกาหลี)
- สำหรับภาษาที่ไม่รองรับ การตั้งค่า
simpleอาจใช้งานได้ดีในทางปฏิบัติ - อย่างไรก็ตาม ยังไม่แน่ชัดว่าเพียงพอสำหรับ CJK หรือไม่
- สำหรับภาษาที่ไม่รองรับ การตั้งค่า
tsquery และการแสดงคิวรี
tsqueryเป็นชนิดข้อมูลที่ใช้แสดงคิวรีค้นหาที่ทำให้เป็นมาตรฐานแล้ว- คำค้นต้องเป็น lexeme ที่ทำให้เป็นมาตรฐานแล้ว
- คำค้นหลายคำสามารถเชื่อมกันด้วยตัวดำเนินการ AND, OR, NOT และ FOLLOWED BY
to_tsquery,plainto_tsquery,websearch_to_tsqueryช่วยเปลี่ยนข้อความที่ผู้ใช้ป้อนให้เป็นtsqueryที่เหมาะสม- บทบาทหลักคือทำให้คำในข้อความอินพุตเป็นมาตรฐาน
- การใช้
websearch_to_tsqueryทำให้สร้างคิวรีที่ใกล้เคียงช่องค้นหาทั่วไปได้darth vaderจะถูกประมวลผลเป็น logical AND ซึ่งหมายความว่าทั้งสองคำต้องอยู่ในเอกสาร- สามารถค้นหาแบบ OR และตัดคำออกได้ด้วย
- การค้นหาวลีจะแสดงรูปแบบที่คำเรียงต่อกันตามลำดับ
- ในการตั้งค่าภาษาอังกฤษ stop words อย่าง “the” จะถูกนำออก ดังนั้นในการค้นหาวลีบางกรณี ข้อความเกือบทั้งวลีอาจหายไป
- ในกรณีเช่นนี้ การใช้การตั้งค่า
simpleจะช่วยให้ได้ผลลัพธ์ตามที่คาดหวัง
- ในกรณีเช่นนี้ การใช้การตั้งค่า
- ตัวดำเนินการ
@@ใช้เมื่อตรวจสอบว่าtsqueryตรงกับtsvectorหรือไม่
GIN index และประสิทธิภาพการค้นหา
- GIN ย่อมาจาก Generalized Inverted Index เป็นชนิด index ที่ออกแบบมาสำหรับคิวรีที่ค้นหาค่าองค์ประกอบภายในค่าประกอบ
- GIN ใช้ได้ทั้งกับการค้นหาข้อความและคิวรี JSON
- สามารถสร้างคอลัมน์
tsvectorที่รวมหลายคอลัมน์ที่ต้องการให้ค้นหาได้ แล้วสร้าง GIN index บนคอลัมน์นั้น - ในสภาพแวดล้อมตัวอย่าง GIN index ลดเวลาค้นหาจาก มากกว่า 200ms เหลือประมาณ 4ms
การจัดอันดับและการคำนวณความเกี่ยวข้อง
- เพื่อประสบการณ์ค้นหาที่ดี ควรเรียงผลลัพธ์ตาม ความเกี่ยวข้อง
- PostgreSQL มีฟังก์ชันจัดอันดับที่กำหนดไว้ล่วงหน้า 2 ตัวคือ
ts_rankและts_rank_cd- ทั้งสองฟังก์ชันคำนึงถึงความถี่ที่คำค้นปรากฏ
ts_rank_cdยังสะท้อนความใกล้กันระหว่าง lexeme ที่ตรงกันด้วย
- ความเกี่ยวข้องขึ้นอยู่กับลักษณะของแอปพลิเคชันอย่างมาก
- ฟังก์ชันจัดอันดับพื้นฐานเป็นเหมือนจุดเริ่มต้น และสามารถสร้างฟังก์ชันจัดอันดับเองหรือผสานกับปัจจัยอื่นได้ตามต้องการ
ts_rankต้องเข้าถึงคอลัมน์searchของแต่ละผลลัพธ์- หากเงื่อนไข
WHEREmatch กับหลายแถว PostgreSQL ต้องเข้าถึงแถวทั้งหมดเพื่อคำนวณอันดับและเรียงลำดับ - ในสภาพแวดล้อมตัวอย่าง คิวรีหนึ่งส่งคืนผลใน 5~7ms แต่คิวรีที่ต้องจัดอันดับผลลัพธ์มากกว่า 1,000 รายการ เช่น
darth OR vaderใช้เวลาประมาณ 80ms
- หากเงื่อนไข
การปรับแต่งความเกี่ยวข้อง
- ความเกี่ยวข้องตามความถี่ของคำเป็นค่าเริ่มต้นที่ดี แต่ข้อมูลอาจมีสัญญาณอื่นที่สำคัญกว่าความถี่
- ในชุดข้อมูลภาพยนตร์ สามารถสะท้อนสัญญาณต่อไปนี้ในความเกี่ยวข้องได้
- ให้ผลลัพธ์ที่ match ในชื่อเรื่องสำคัญกว่าผลลัพธ์ที่ match ในคำอธิบายหรือเรื่องย่อ
- ดันภาพยนตร์ที่ได้รับความนิยมมากขึ้นโดยอิงจากคะแนนหรือจำนวนโหวต
- หากผู้ใช้ชอบคอเมดี้ ให้จัดภาพยนตร์คอเมดี้ไว้สูงขึ้น
- มองว่าชื่อเรื่องใหม่ ๆ มีความเกี่ยวข้องมากกว่าชื่อเรื่องเก่า
- เสิร์ชเอนจินเฉพาะทางมีฟังก์ชันสำหรับกำหนดให้คอลัมน์หรือฟิลด์ต่าง ๆ ส่งผลต่ออันดับ
- ตัวอย่างเอกสารที่เกี่ยวข้องดูได้ที่ Elastic, Typesense, Meilisearch
การ boost ตามตัวเลข วันที่ และค่าที่ตรงตัว
- PostgreSQL ไม่ได้มีการ boost ตามคอลัมน์อื่นให้โดยตรง แต่สุดท้ายแล้วการจัดอันดับก็คือ นิพจน์การเรียงลำดับ จึงสามารถเพิ่มสัญญาณของเราเองเข้าไปได้
- หากต้องการสะท้อนจำนวนโหวต สามารถทำได้โดยเพิ่ม boost ตามจำนวนโหวตเข้าไปในคะแนนอันดับ
- ในตัวอย่างใช้ลอการิทึมเพื่อทำให้อิทธิพลเพิ่มขึ้นอย่างค่อยเป็นค่อยไป
- ใช้ค่าสัมประสิทธิ์
0.01เพื่อปรับ booster ให้อยู่ในสเกลใกล้เคียงกับคะแนนอันดับ
- สามารถสร้างฟังก์ชันที่ซับซ้อนขึ้นเพื่อ boost คะแนนเฉพาะเมื่อจำนวนโหวตถึงระดับหนึ่งได้
- หากต้องการดันประเภทใดประเภทหนึ่ง สามารถใช้ฟังก์ชันอย่าง
valueBoosterที่คืนค่าสัมประสิทธิ์เฉพาะเมื่อค่าตรงกับค่าคอลัมน์ที่กำหนด
น้ำหนักของคอลัมน์
- lexeme ใน
tsvectorสามารถติด น้ำหนัก ได้ - PostgreSQL รองรับน้ำหนัก 4 ระดับคือ A, B, C, D
- A เป็นน้ำหนักสูงสุด
- D เป็นน้ำหนักต่ำสุดและเป็นค่าเริ่มต้น
- สามารถใช้ฟังก์ชัน
setweightเพื่อควบคุมน้ำหนักเมื่อสร้างคอลัมน์tsvector - เมื่อให้น้ำหนักสูงขึ้นกับคอลัมน์ชื่อเรื่อง ภาพยนตร์ที่มีคำค้นในชื่อเรื่องจะถูกดันขึ้นไปด้านบนของผลลัพธ์ และคะแนนอันดับก็เพิ่มขึ้นด้วย
- ข้อจำกัดคือมี weight class เพียงสี่ระดับ และต้องใช้ weight ตอนคำนวณ
tsvector
การรองรับคำสะกดผิดและ fuzzy search
- PostgreSQL ไม่รองรับ fuzzy search หรือการรองรับคำสะกดผิดโดยตรงเมื่อใช้
tsvectorและtsquery - ภายใต้สมมติฐานว่าคิวรีมีคำสะกดผิด สามารถทำได้ด้วยวิธีต่อไปนี้
- index lexeme ทั้งหมดจากเนื้อหาไว้ในตารางแยก
- ค้นหาคำผู้สมัครสำหรับแต่ละคำในคิวรีด้วย similarity หรือ Levenshtein distance
- แก้คิวรีให้รวมคำที่พบ
- ค้นหาด้วยคิวรีที่แก้แล้ว
- ในตัวอย่างใช้ Levenshtein distance เพราะเป็นวิธีที่เสิร์ชเอนจินต่าง ๆ ใช้สำหรับ fuzzy search
- หลังจากได้รายการคำผู้สมัครแล้ว ต้องปรับคิวรีให้รวมคำเหล่านั้นทั้งหมด
Faceted search
- Faceted search ใช้อย่างแพร่หลาย โดยเฉพาะในเว็บไซต์อีคอมเมิร์ซ เพื่อให้ผู้ใช้ค่อย ๆ จำกัดขอบเขตการค้นหาซ้ำ ๆ
- ใน PostgreSQL สามารถทำได้โดยกำหนดหมวดหมู่ด้วยตนเองแล้วเพิ่มเป็นเงื่อนไข
WHEREของการค้นหา - อีกวิธีที่เป็นไปได้คือสร้างหมวดหมู่เชิงอัลกอริทึมจากข้อมูลที่มีอยู่
- ในตัวอย่างสร้าง facet “Decade” จากปีของภาพยนตร์
- สามารถคำนวณจำนวน match ของแต่ละ decade แล้วแสดงในวงเล็บได้
- หากต้องการดึงหลาย facet ในคิวรีเดียว สามารถผสาน CTE ได้
- วิธีนี้อาจทำงานได้ดีในชุดข้อมูลขนาดเล็กถึงกลาง แต่เมื่อเป็นชุดข้อมูลใหญ่มากอาจช้าลงได้
ขอบเขตและข้อจำกัดของเสิร์ชเอนจิน PostgreSQL
- เมื่อนำองค์ประกอบการค้นหาข้อความแบบเต็มของ PostgreSQL มาผสานกัน ก็สามารถสร้างเสิร์ชเอนจินที่ค่อนข้างขั้นสูงได้
- การค้นหาบน PostgreSQL ยังรองรับ join และ ACID transaction ไปพร้อมกันด้วย
- สิ่งเหล่านี้เป็นฟีเจอร์ที่เสิร์ชเอนจินอื่นโดยทั่วไปไม่มี
- หัวข้อการค้นหาขั้นสูงที่ยังน่ากล่าวถึงเพิ่มเติมมีดังนี้
- คำแนะนำและ autocomplete
- การ match วลีแบบตรงตัว
- hybrid search ที่ผสานกับ
pg-vector
- ฟีเจอร์เหล่านี้ทำได้ด้วย PostgreSQL แต่ต้องประกอบองค์ประกอบต่าง ๆ เอง
- ในบางกรณี ประสิทธิภาพอาจลดลงกับชุดข้อมูลขนาดใหญ่มาก
- บทความต่อเนื่อง part 2 เปรียบเทียบระหว่างการทำ search ใน PostgreSQL กับการเพิ่ม Elasticsearch เข้าไปในโครงสร้างพื้นฐานและซิงก์ข้อมูล
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
ไม่ควรพยายามทำสิ่งนี้ด้วย วิธีเลียนแบบฟีเจอร์ของ Elasticsearch
ในยุคปี 2000 ผมเคยสร้างเสิร์ชเอนจินด้วย MySQL 3.x ที่พาร์สข้อมูล EXIF ของรูปภาพ แล้วทำดัชนีระบบหมวดหมู่ 3 ระดับพร้อมจำนวนรายการ ซึ่งเป็นสิ่งที่แม้แต่ผู้ขายราคาแพงหลายรายก็ยังทำได้ไม่ดี และ Autonomy ยังทำไม่ได้แม้กระทั่งหมวดหมู่ระดับบนสุด
ตลอด 6 สัปดาห์ ผมแทบจะทำสำเร็จด้วยการเขียน SQL ที่เปราะบางจนแค่เปลี่ยนลำดับคอลัมน์ใน SELECT ประสิทธิภาพก็เปลี่ยน แต่ไม่อยากทำอีกแล้ว แม้ฐานข้อมูลโดยแก่นแล้วจะคล้ายกันมาก แต่ เสิร์ชเอนจินพัฒนาไปไกลกว่ามาก
ทำเพื่อความอยากรู้อยากเห็นทางปัญญาได้ แต่การค้นหาไม่ใช่แค่ tokenize แล้วจบ ไม่นานก็จะมีความต้องการอย่างการนำทางตามหมวดหมู่, หลายภาษา, คำพ้องอัตโนมัติ, คำแนะนำสะกดแบบ "Did you mean", ประสิทธิภาพระดับใหญ่ และสุดท้ายคุณจะติดอยู่ในทางตันเอง เพื่อสุขภาพจิต ใช้เสิร์ชเอนจินจะดีกว่า และสำหรับการ sync ระหว่าง PG กับ ES ก็มีเครื่องมืออย่าง ZomboDB หรือ PGSync
ในทางกลับกัน ถ้านักวิเคราะห์ข้อมูลหรือนักพัฒนาต้องการค้นหาคอลัมน์ข้อความในฐานข้อมูลขนาดใหญ่ให้ยืดหยุ่นกว่า
LIKE/ILIKEการสร้าง ดัชนี/ตาราง full-text search ไว้ในฐานข้อมูลเดียวกันอาจง่ายและเร็วกว่าในการไปให้ถึง 90%รออ่านภาค 2 ที่เปรียบเทียบ Postgres vs Elasticsearch แอปหนึ่งของบริษัทใช้ PG สำหรับ CRUD ของออบเจ็กต์ และใช้ Elastic สำหรับค้นหา แต่ประเมินความพยายามในการ sync data store ทั้งสองต่ำไปมาก และตอนนี้กำลังพิจารณาเอา Elasticsearch ออกจริง ๆ
ทุก 5 นาที cron จะหาออบเจ็กต์เป้าหมายสำหรับทำดัชนีจาก DB ที่มี
last_modified_at > last_indexing_started_timestampแล้วทำดัชนีเข้า Elasticsearch จากนั้นอัปเดตlast_indexing_started_timestampเป็นเวลาที่เริ่ม sync วิธีนี้ออบเจ็กต์ที่ถูกแก้ไขระหว่างเริ่มและจบการรัน จะถูกจับได้ในการรันถัดไปถ้าต้องสร้าง Elasticsearch ใหม่ ก็ล้างเวลาทำดัชนีล่าสุดแล้ว sync ใหม่ตั้งแต่ต้นได้ และเพราะมันกู้คืนตัวเองได้ การ sync จึงไม่เพี้ยน
งาน async ก็เหมือนทั่วไปที่ต้องมี monitoring และ retry แต่ ES เสถียรและเร็ว ปัญหาจึงพบไม่บ่อย อย่างไรก็ตามข้อกำหนดด้าน consistency ค่อนข้างผ่อนคลาย แค่สถานะล่าสุดของ PG ไปถึง ES ภายในเวลาที่สมเหตุสมผลก็พอ ดังนั้นถ้าข้อกำหนดต่างกัน ผลก็อาจต่างกันได้
หลังย้ายมาใช้ full-text search ของ Postgres พร้อมใส่น้ำหนักให้ดัชนีและคิวรี ก็สามารถจัดการทุกอย่างที่ต้องการภายใน Postgres ได้ด้วย update trigger และ search query ที่เร็วมาก
โดยรวมถือว่าสำเร็จ และลดภาระปฏิบัติการลงมากจนคุ้มกับเวลาวิศวกรรมที่ลงไป แต่ไม่ใช่เรื่องที่ควรเริ่มแบบเบา ๆ
แล้วแต่ความต้องการ materialized view, view ปกติ, trigger อาจดีกว่า การค้นหาข้อความในตัวอาจไม่เหมาะกับ use case และการสร้างทางเลือกเองก็ไม่ได้ยากเสมอไป
ถ้าไม่มี เวลา query p50/p99 ภายใต้โหลดที่สมจริง ก็ยากจะบอกว่าพิสูจน์แล้ว เสิร์ชเอนจินที่คืนผลใน 1 นาทีไม่ใช่ "ขั้นสูง" และฐานข้อมูลเชิงสัมพันธ์อย่าง Postgres แน่นอนว่าทำได้บนกระดาษ
โดยรวมเห็นด้วย และถ้าเป็นสเกลใหญ่ เช่น มากกว่าหลายล้านเรคคอร์ด ก็คงไม่น่าใช้วิธีนี้ ความสนใจหลักคือดูว่าสามารถจำลองฟีเจอร์ได้มากแค่ไหน
สำหรับ use case ค้นหาขนาดเล็ก ข้อดีคือมีอินฟราที่ต้องดูแลน้อยกว่า มี strong consistency และ join ได้ ที่ Xata ก็กำลังคิดถึงเส้นทางย้ายผ่านที่นุ่มนวลจากการใช้ Postgres ในสเกลเล็กไปสู่ Elasticsearch โดยมี breaking change ให้น้อยที่สุด
จากมุมมองนั้น ผลการค้นหาที่เร็วเองไม่ได้ดูน่าทึ่งมาก เพราะสามารถอัปเดตผลลัพธ์ใน cache ด้วยงาน background ไว้ตลอด แล้วพอมี request ก็ส่งกลับไปได้เลย การ cache และเวลาตอบสนอง แบบนี้ดูเป็นคนละเรื่องกับความเร็วในการคำนวณผลการค้นหาจริง
บางคนใช้การเชื่อมต่อที่ช้า และคำค้นเฉพาะอย่างแผ่นดินไหวก็อาจพุ่งขึ้นเฉพาะในบางภูมิภาคเท่านั้น
ถ้าคำค้นสุ่มเกินไป cache จะไม่มีผลลัพธ์ ทำให้ดูแย่กว่าความจริง แต่ถ้าไม่สุ่มพอ ก็จะดูดีกว่าความจริง
ดังนั้นข้อดีของ ES และเครื่องมือทำนองนั้นจึงอยู่ที่การ scale แนวนอนข้ามหลาย node หรือฟีเจอร์เสริมที่วางทับบนดัชนีหลัก
ถ้าใช้แค่
ts_rankก็สมบูรณ์แบบ แต่โดยปกติจะอยากปรับอันดับด้วย ตัวชี้วัดความเกี่ยวข้อง อื่น ๆ หากแก้จุดที่ไม่สามารถใช้ตัวชี้วัดนั้นเป็นเกณฑ์อันดับหลักได้ ผลลัพธ์ก็จะเร็วพอ ๆ กับการ query ตาราง DB ปกติที่มีดัชนีตอนวัยรุ่นเคยลองสร้างทั้งเสิร์ชเอนจินและฐานข้อมูลขึ้นมาเองตั้งแต่ศูนย์ ทั้งที่ยังไม่ค่อยรู้อะไรเกี่ยวกับทั้งสองอย่าง อยากดูว่าจะไปได้ไกลแค่ไหน และจะคืนผลการค้นหาที่เกี่ยวข้องได้เร็วระดับไหน
การสร้างฐานข้อมูลและเสิร์ชเอนจินแบบพื้นฐานอย่างรวดเร็วถือว่าค่อนข้างง่าย แม้แต่สำหรับโปรแกรมเมอร์สมัครเล่น ถ้าเข้าใจอัลกอริทึมวิทยาการคอมพิวเตอร์พื้นฐาน และวิธีใช้ระบบปฏิบัติการ/ฮาร์ดแวร์ ก็ทำได้ภายในหนึ่งถึงสองเดือน
แม้ใช้ภาษาระดับสูง ความเร็วก็ไม่ได้แย่ ประมาณ 250,000 QPS บนแล็ปท็อปปี 2003 ถ้าทำชาร์ดดิ้ง ความสามารถในการขยายก็ไม่ใช่ปัญหาใหญ่ สิ่งที่ซับซ้อนกว่าการเก็บและดึงข้อมูลคือการทำดัชนี การล็อก และความสอดคล้องของข้อมูล
ปัญหาใหญ่จริง ๆ คือ ความเป็นอัตวิสัย ของการค้นหา พอเป็นเรื่องว่าจะหาสิ่งที่ต้องการจริง ๆ ได้อย่างไร, จะหาอย่างไรเมื่อแม้แต่ตัวเองก็ไม่รู้ว่ากำลังหาอะไร, จะป้องกันคนที่พยายามใช้ระบบในทางที่ผิดอย่างไร, และจะจัดการคิวรีกับชุดข้อมูลที่ซับซ้อนอย่างไร ระดับความยากก็เพิ่มขึ้นไปอีกหลายหลัก
เลยสงสัยว่าจริง ๆ แล้วใช้ ฐานข้อมูลอเนกประสงค์ หรือเปล่า และตัวเลขนั้นถูกต้องไหม อยากรู้ว่าใช้เทคนิคอะไรถึงเอาชนะเอนจินพวกนี้ได้
ถ้าใหญ่กว่านั้นก็ต้องใช้วิธีแก้ที่สร้างสรรค์ และตั้งแต่นั้นเป็นต้นไปก็จะมี trade-off หลายอย่างตามมา
หนึ่งในปัญหาหลายอย่างของการค้นหาภายใน Postgres คือการค้นหาเป็นงานที่ ใช้ CPU หนัก และแนวโน้มก็กำลังไปทางการใช้ GPU มากขึ้นด้วย ตามอุดมคติแล้ว เราอยากเหลือ CPU ของฐานข้อมูลไว้สำหรับการอัปเดตแบบทรานแซกชันของโมเดลข้อมูลหลัก
เคยเห็นคลัสเตอร์ ES และ Solr ตอน reindex ใช้ CPU 100% บนโหนดมากกว่า 10 ตัว หรือแม้เวลาปกติก็ใช้ 30–50% บนโหนดมากกว่า 10 ตัวอยู่บ่อย ๆ ฐานข้อมูลที่สอดคล้องกันอาจเป็นเช่น instance AWS L/XL ที่มีข้อมูล 50–100GB และใช้ CPU ราว 30%
ถ้าย้าย CPU สำหรับค้นหาทั้งหมดไปไว้ที่ DB หลัก ตอนนี้ก็ต้องชาร์ด DB แล้ว อย่างไรก็ตาม สำหรับโปรเจกต์ส่วนตัว ส่วนขยายของ PG สำหรับการค้นหา, recursive join, เวกเตอร์ ฯลฯ นั้นสนุกและเรียบง่ายดี
เคยทำแบบนี้จริงมาก่อน และทำให้ค่อนข้างเร็วได้
https://austingwalters.com/fast-full-text-search-in-postgres...
เว็บไซต์ปัจจุบันคือ https://askhn.ai
[1]: https://en.wikipedia.org/wiki/Kerning
ถ้าผสมเทคนิคแบบนี้กับ pgvector ก็จะสามารถหาเนื้อหาที่เกี่ยวข้องด้วย embedding ได้ด้วย รู้สึกเหมือนเวทมนตร์ทีเดียว
อนึ่ง ไม่ใช่ "Dark" Vader แต่เป็น Darth Vader ผมเองตอนเด็กก็เคยคิดว่าเป็น "Dark" เหมือนกัน
เป็นบทความที่ดีและชัดเจนมาก SQLite ก็มี ความสามารถทำดัชนีขั้นสูงและการตัดรากคำ ให้เป็นปลั๊กอินมาตรฐานเช่นกัน
ถ้าเป็นภาษาอังกฤษ SQLite ก็ทำงานได้ดี
https://github.com/daitangio/knowledge
ลองใช้ดูน่าจะดี ค่อนข้างทรงพลัง
เป็นบทความที่ดี แต่ส่วนที่บอกว่า PostgreSQL ไม่รองรับ fuzzy search นั้นผิดบางส่วน ส่วนขยาย
pg_trgmและดัชนี GIN trigram รองรับ use case การค้นหาแบบ fuzzy อย่างตัวอย่างในบทความนี้https://www.postgresonline.com/article_pfriendly/169.html
คิวรีอาจเร็วขึ้นมาก แต่ก็มีต้นทุนคือใช้หน่วยความจำมากขึ้นและใช้เวลาทำงานมากขึ้นตอนอัปเดต