Drupal 7 core search (dirty hack) สำหรับภาษาไทย

สืบเนื่อง จากโพสต์ที่แล้ว และ จากปัญหาที่คาใจมานานว่าทำไม Drupal ค้นหาภาษาไทยไม่ได้ พอดี @poakpong เข้ามาทักว่าถ้าจัดการอะไรกับเซิร์ฟเวอร์ไม่ได้เลย แล้วจะทำยังไงให้ Drupal ค้นหาภาษาไทยได้ (ไม่เอา Google CSE ด้วย)

ขั้นแรกเลยลองสร้าง full-text search แบบคร่าวๆด้วย search_api + search_api_db ก็โอเค แต่ยังคาใจอยู่ว่าทำไมผลการค้นหามันเพี้ยนๆ เช็ค database ดู ก็พบว่า Drupal ตัดสระและวรรณยุกต์ไทยบนล่างทิ้งหมดก่อนจะเก็บ index

ตื่นมายังไม่หายแคลงใจ เพราะ Drupal มี hook_search_preprocess() ไว้ให้ แปลว่าเราต้องทำอะไรกับ search index ได้มากกว่านี้แน่ แต่ขี้เกียจเขียน module ใหม่ เลยลอง hack core search ดู พอเปิดไฟล์ modules/search/search.module ของ Drupal 7.10 ก็พบว่า PREG_CLASS_SEARCH_EXCLUDE ไม่มีแล้ว!

แบบนี้ก็ hack ไวๆแบบหน้าด้านๆได้เลย แค่เปลี่ยน Unicode range ของตัวอักษรจีน ญี่ปุ่น เกาหลี (CJK) ที่เขียนแบบไม่มีช่องว่างระหว่างคำแบบเดียวกับเรา ให้เป็น Unicode range ของตัวอักษรไทย (0E01-0E3A,0E3F-0E5B น่าจะครบทุกตัวนะ?) แก้ PREG_CLASS_CJK (แถวๆบรรทัดที่ 54) เป็น

define('PREG_CLASS_CJK', '\x{0E01}-\x{0E3A}\x{0E3F}-\x{0E5B}');

แก้ multibyte error โดยเปลี่ยนมาใช้ strlen() แทน drupal_strlen() (บรรทัดที่ 1188)

$s = min($s, strlen($end) - 1);

เปิดใช้งาน core search แล้วดูตรง indexing settings เลือก Simple CJK handling (minimum word length 3 ตัวอักษร ก็คง make sense มั้ง?) แล้วก็ reindex รัน cron จนกว่ามันจะ index ครบ 100%

จริงๆมันมีวิธีที่ดีกว่านี้แน่ๆ แต่ผมขี้เกียจ อย่างที่บอกไป ถ้าใช้ hook_search_preprocess() น่าจะเนียนกว่าเยอะ แต่ hack ง่ายๆไว้พอเป็นไอเดียให้ทำ module สำหรับค้นหาภาษาไทยต่อไป (ถ้าไม่ลืม) และคงพอจะแก้ปัญหาเฉพาะหน้าได้สำหรับคนที่ไม่ใส่ใจ Drupal code standard / convention เท่าไหร่

ผม patch ทิ้งไว้ที่ https://gist.github.com/1509489 เผื่อใครใช้ git (ดาวน์โหลด patch แล้วก็ git apply http://drupal.org/node/707484) เท่าที่ทดสอบค้นภาษาไทยก็ไม่ยังเจอปัญหาอะไรนะ แต่ดูเหมือนมันจะ index ช้ามากๆ หรือเพราะผมชินกับ Solr indexing ก็ไม่แน่ใจ

ส่วนการตัดคำไทยก่อน index เป็นอีกเรื่องนึงนะครับ ตอนนี้ผมทำได้แค่ให้มันเก็บ index ตัวอักษรไทยให้เป็น search tokens (ชิ้นส่วนสำหรับประกอบเป็นคำไทย) โดยไม่ต้องอาศัยแค่ช่องว่างระหว่างประโยค

Edit: พบว่า PREG_CLASS_SEARCH_EXCLUDE ไม่ได้หายไป แต่เปลี่ยนเป็น PREG_CLASS_UNICODE_WORD_BOUNDARY ในไฟล์ includes/unicode.inc แต่ไม่น่ามีปัญหาอะไร เพราะถ้าดูไม่ผิด Drupal ใช้ตัวอักษรไทยไว้ตัดคำแค่ 4 ตัว? E3F(฿), E4F(๏), E5A(๚), E5B(๛)