บทความ ของขวัญปีใหม่ "ตัดคำภาษาไทย" แล้วก็วิธีการ Search แบบ Fulltext
บทความนี้ผมถือว่าเป็นของขวัญปีใหม่สำหรับ Developer ทุกคนที่ติดตาม jQueryTips.com นะครับ เพราะว่า คุณจะหาอ่านบทความเรื่องนี้แบบครบถ้วนที่ไหนไม่ได้อีกแล้ว เพราะว่า English Text ก้ไม่มี เพราะมันเป็นเรื่อง Algorithm ของการตัดคำภาษาไทย 555+
บทความนี้จะขอแบ่งออกเป็น 2 ตอนนะครับ โดยเนื้อหาในส่วนแรกจะเป็นเรื่องของ "การตัดคำภาษาไทย" ส่วนเรื่องที่ 2 จะเป็นการประยุกต์ใช้งาน กับคำที่เราได้ออกมากับ "Zend_Search_Lucene"
เอาล่ะเรามาเริ่มเนื้อหาในส่วนของตอนแรกกันดีกว่า...
เรื่องการตัดคำนั้นมันเป็นเรื่องหน้าหนักใจจริงๆ ครับในส่วนของภาษาไทย เพราะว่า Software ที่ทำมาส่วนมากมันจะรองรับ กับ International language ก่อน นั่นก็คือ ภาษาอังกฤษ ต่อมาก็พวก Spainish แล้วก็ไล่มาเรื่อยๆ จนท้ายๆ น่ะมันถึงจะหันมามองเรา ซึ่งการตัดคำในภาษาอื่นมันก็แสนจะง่ายดายไม่มีอะไรซับซ้อน เพราะว่ามันสามารถตัดกันได้ที่ช่องไฟอยู่แล้ว
แต่ภาษาแม่เรามันดันไม่มีช่องไฟ เพื่อที่จะให้มันทำการตัดคำ "เรื่องใหญ่เลยนะ" เพราะว่า ถ้าเราแยกคำไม่ออก เราก็ไม่สามารถเอาไปทำพวก ระบบค้นหาแบบ Fulltext ได้เลย นอกจากหนีไปใช้ Algorithm แบบ N-gram ที่ใช้วิธีการตัด ทุกๆตัวอักษร ทำให้ผลลัพธ์ที่ได้ ขาดความแม่นยำ และเสียพื้นที่การจัดเก็บสูง ซึ่งตัวตัดคำนี้ก้มีหลายตัวด้วยกัน แต่ที่ผมจะเอามาทดลอง วันนี้ชื่อว่า "swath" ครับ ซึ่งผู้พัฒนาก็คือ NECTEC นั่นเองครับ
ก็ขอให้ Credit มา ณ ที่นี้ด้วย
สำหรับข้อมูลเบื้องต้นผมไปค้นจาก Wiki เจอมาตามลิ้งก์ทางด้านล่างครับ
http://braille.coe.psu.ac.th/mediawiki/index.php/Linux_UI_and_Front-end_Operation#SWATH
ภาพตัวอย่างผลลัพธ์ของการตัดคำที่ได้ออกมา

ตัวลิ้งก์ที่ให้ Download นั้นมีทั้ง ระบบปฎิบัติการ Windows และ Linux ด้วยกัน
Windows: http://www.hlt.nectec.or.th/products/swath-win32-console.zip
Linux: http://www.hlt.nectec.or.th/products/swath-0.2pre2-glibc2.1.1.i386.tar.gz
วิธีการใช้งานไม่มีอะไรซับซ้อนเลยสักนิด
ถ้ามาลองไล่ตามโคดก่อนก็คือ ไปสร้าง Temp file รอไว้สำหรับทำ input และ output เพราะว่าถ้าเราส่งเป็น string เข้าไปเลย ตัว swath มันจะมีข้อจำกัด ที่ไม่พอต่อการใช้งาน เลยใช้วิธีสร้าง Temp file เข้าไปดีกว่า
จากนั้นถ้าใครใช้ UTF-8 ก็ต้อง Convert ให้เป็น TIS-620 เพราะตัว swath จะตัดคำตาม Encoding นี้เท่านั้น ต่อจากนั้นมาดูที่ตการเรียกใช้งาน
ตามโคดนี้ผมใช้ในระบบปฎิบัติการ Windows นะครับ
ตัว -b หมายถึง ผมจะให้แยกคำด้วย ไปท์ ก็คือ -b "|"
ตัว -d swath หมายความว่า Folder Data ของ Swath อยู่ตรงนั้น ซึ่ง folder นี้สังเกตุง่ายๆ มันจะมี 3 ไฟล์นี้อยู่

ตัว -m หมายถึงว่าเราจะเลือกใช้ ลักษณะการตัดคำแบบไหน ซึ่้งแต่ละแบบเป็นยังไง อ่านได้จาก ลิ้งอ้างอิงทางด้านล่างครับ
http://braille.coe.psu.ac.th/mediawiki/index.php/Linux_UI_and_Front-end_Operation#SWATH
ต่อจากนั้นก็กำหนด พาธ ของ I/O เท่านี้ก็รอผลลัพธ์อย่างเดียวเลย เดี๋ยวเค้าจัดให้เสร็จ 555+
พอเราได้ข้อมูลออกมาทาง Output แล้ว ก็มา Convert กลับจาก TIS-620 > UTF-8 (ในกรณีที่เว็บใช้ UTF-8)
จากนั้นก็ลบ Temp file ทิ้งได้เลยครับ ลองมาดูผลงานทดสอบดู
1. ภาพแรกเป็นภาพของ Text ที่ผมทำการพิมพ์เข้าไป

2. ภาพที่สองเป็นผลลัพธ์ ที่ได้จากการ Submit แล้ว

จะเห็นได้ว่าตัวโปรแกรมทำการตัดคำภาษาไทยได้ค่อนข้างดี อาทิเช่นคำว่า "นม" กับ "ขนม" โปรแกรมก็สามารถแยกออกได้ ทีนี้ก็เหลืออีกโจทย์คือว่า แล้วเราจะเอามันไปทำอะไรดีล่ะ ??
ซึ่ง Basic ที่สุดก็คือนำมันไปทำระบบจัดเก็บ ดัชนีเพื่อทำการค้นหา แต่ว่าจริงๆ แล้วผมว่ามันมีประโยชน์มากมายเลยนะ อาทิเช่น เอาไปทำระบบ Relate สินค้า อะไรพวกนั้นก็เป็น ไอเดียที่ไม่เลว
เดี๋ยวครั้งหน้าเราลองดูว่าจะเอามันมาทำระบบ Search แบบ Fulltext ได้ยังไงก่อนก็แล้วครับ
สุดท้ายก็ "สวัสดีปีใหม่ โชคดีมีชับ ร่ำรวยกันทุกๆ คนนะครับ"
Tee++;
บทความนี้จะขอแบ่งออกเป็น 2 ตอนนะครับ โดยเนื้อหาในส่วนแรกจะเป็นเรื่องของ "การตัดคำภาษาไทย" ส่วนเรื่องที่ 2 จะเป็นการประยุกต์ใช้งาน กับคำที่เราได้ออกมากับ "Zend_Search_Lucene"
เอาล่ะเรามาเริ่มเนื้อหาในส่วนของตอนแรกกันดีกว่า...
เรื่องการตัดคำนั้นมันเป็นเรื่องหน้าหนักใจจริงๆ ครับในส่วนของภาษาไทย เพราะว่า Software ที่ทำมาส่วนมากมันจะรองรับ กับ International language ก่อน นั่นก็คือ ภาษาอังกฤษ ต่อมาก็พวก Spainish แล้วก็ไล่มาเรื่อยๆ จนท้ายๆ น่ะมันถึงจะหันมามองเรา ซึ่งการตัดคำในภาษาอื่นมันก็แสนจะง่ายดายไม่มีอะไรซับซ้อน เพราะว่ามันสามารถตัดกันได้ที่ช่องไฟอยู่แล้ว
แต่ภาษาแม่เรามันดันไม่มีช่องไฟ เพื่อที่จะให้มันทำการตัดคำ "เรื่องใหญ่เลยนะ" เพราะว่า ถ้าเราแยกคำไม่ออก เราก็ไม่สามารถเอาไปทำพวก ระบบค้นหาแบบ Fulltext ได้เลย นอกจากหนีไปใช้ Algorithm แบบ N-gram ที่ใช้วิธีการตัด ทุกๆตัวอักษร ทำให้ผลลัพธ์ที่ได้ ขาดความแม่นยำ และเสียพื้นที่การจัดเก็บสูง ซึ่งตัวตัดคำนี้ก้มีหลายตัวด้วยกัน แต่ที่ผมจะเอามาทดลอง วันนี้ชื่อว่า "swath" ครับ ซึ่งผู้พัฒนาก็คือ NECTEC นั่นเองครับ
ซึ่งคนที่ไป Labs มาให้ รวมถึงเทสการทำงานเขียน function เบื้องต้น มาให้ก็คือ @FordAntiTrust นั้นเองครับ
ก็ขอให้ Credit มา ณ ที่นี้ด้วย
สำหรับข้อมูลเบื้องต้นผมไปค้นจาก Wiki เจอมาตามลิ้งก์ทางด้านล่างครับ
http://braille.coe.psu.ac.th/mediawiki/index.php/Linux_UI_and_Front-end_Operation#SWATH
ภาพตัวอย่างผลลัพธ์ของการตัดคำที่ได้ออกมา

ตัวลิ้งก์ที่ให้ Download นั้นมีทั้ง ระบบปฎิบัติการ Windows และ Linux ด้วยกัน
Windows: http://www.hlt.nectec.or.th/products/swath-win32-console.zip
Linux: http://www.hlt.nectec.or.th/products/swath-0.2pre2-glibc2.1.1.i386.tar.gz
วิธีการใช้งานไม่มีอะไรซับซ้อนเลยสักนิด
header('Content-Type:text/html;charset=UTF-8');
define('SWATH', dirname(__FILE__) . '/bin/swath4');
function swath($input_text)
{
$input_filename= tempnam("/tmp", "swath_");
$output_filename= tempnam("/tmp", "swath_");
$input_text = iconv('UTF-8', 'TIS-620', trim($input_text));
file_put_contents($input_filename, $input_text);
system(SWATH . '/swath.exe -b "|" -d ' . SWATH . '/swath -m long < ' . $input_filename . ' > ' . $output_filename);
$raw = file_get_contents($output_filename);
$raw = iconv('TIS-620', 'UTF-8', rtrim($raw));
$raw = preg_replace('/| |/', '|', $raw);
unlink($input_filename);
unlink($output_filename);
return preg_split('/|/', $raw, -1, PREG_SPLIT_NO_EMPTY);
}
ถ้ามาลองไล่ตามโคดก่อนก็คือ ไปสร้าง Temp file รอไว้สำหรับทำ input และ output เพราะว่าถ้าเราส่งเป็น string เข้าไปเลย ตัว swath มันจะมีข้อจำกัด ที่ไม่พอต่อการใช้งาน เลยใช้วิธีสร้าง Temp file เข้าไปดีกว่า
จากนั้นถ้าใครใช้ UTF-8 ก็ต้อง Convert ให้เป็น TIS-620 เพราะตัว swath จะตัดคำตาม Encoding นี้เท่านั้น ต่อจากนั้นมาดูที่ตการเรียกใช้งาน
ตามโคดนี้ผมใช้ในระบบปฎิบัติการ Windows นะครับ
system(SWATH . '/swath.exe -b "|" -d ' . SWATH . '/swath -m long < ' . $input_filename . ' > ' . $output_filename);
ตัว -b หมายถึง ผมจะให้แยกคำด้วย ไปท์ ก็คือ -b "|"
ตัว -d swath หมายความว่า Folder Data ของ Swath อยู่ตรงนั้น ซึ่ง folder นี้สังเกตุง่ายๆ มันจะมี 3 ไฟล์นี้อยู่

ตัว -m หมายถึงว่าเราจะเลือกใช้ ลักษณะการตัดคำแบบไหน ซึ่้งแต่ละแบบเป็นยังไง อ่านได้จาก ลิ้งอ้างอิงทางด้านล่างครับ
http://braille.coe.psu.ac.th/mediawiki/index.php/Linux_UI_and_Front-end_Operation#SWATH
ต่อจากนั้นก็กำหนด พาธ ของ I/O เท่านี้ก็รอผลลัพธ์อย่างเดียวเลย เดี๋ยวเค้าจัดให้เสร็จ 555+
พอเราได้ข้อมูลออกมาทาง Output แล้ว ก็มา Convert กลับจาก TIS-620 > UTF-8 (ในกรณีที่เว็บใช้ UTF-8)
จากนั้นก็ลบ Temp file ทิ้งได้เลยครับ ลองมาดูผลงานทดสอบดู
1. ภาพแรกเป็นภาพของ Text ที่ผมทำการพิมพ์เข้าไป

2. ภาพที่สองเป็นผลลัพธ์ ที่ได้จากการ Submit แล้ว

จะเห็นได้ว่าตัวโปรแกรมทำการตัดคำภาษาไทยได้ค่อนข้างดี อาทิเช่นคำว่า "นม" กับ "ขนม" โปรแกรมก็สามารถแยกออกได้ ทีนี้ก็เหลืออีกโจทย์คือว่า แล้วเราจะเอามันไปทำอะไรดีล่ะ ??
ซึ่ง Basic ที่สุดก็คือนำมันไปทำระบบจัดเก็บ ดัชนีเพื่อทำการค้นหา แต่ว่าจริงๆ แล้วผมว่ามันมีประโยชน์มากมายเลยนะ อาทิเช่น เอาไปทำระบบ Relate สินค้า อะไรพวกนั้นก็เป็น ไอเดียที่ไม่เลว
เดี๋ยวครั้งหน้าเราลองดูว่าจะเอามันมาทำระบบ Search แบบ Fulltext ได้ยังไงก่อนก็แล้วครับ
สุดท้ายก็ "สวัสดีปีใหม่ โชคดีมีชับ ร่ำรวยกันทุกๆ คนนะครับ"
Tee++;

32 comments