Tôi, PHP và Lucene

Lucene là thư viện Java mã mở nổi tiếng giúp bạn xây dựng một “Google-like search engine”. Nếu bạn là Java coder thì đến 99% bạn đã nghe đến Lucene, mức độ thành công của nó được thể hiện qua số lượng bản port sang hầu hết các ngôn ngữ phổ biến: C++, C, C#, Ruby, Python, PHP … Lucene được sử dụng trong rất nhiều website, ứng dụng nổi tiếng như Wikipedia, Technorati … cho đến Eclipse IDE.

Trong quá trình làm project của mình, tôi có dịp được nghiên cứu về một số phiên bản của Lucene, quá trình nghiên cứu và test này thú vị đến nỗi tôi không thể không post lên đây được. 

Nói qua về Lucene cho ai chưa hiểu: Lucene là một thư viện các lớp, sử dụng nó, bạn có thể xây dựng các ứng dụng full-text search hoặc nhúng tính năng này vào ứng dụng của mình. Công việc của Lucene gồm 2 phần: Indexing là công việc phân tích, đánh chỉ mục tài liệu text của bạn và searching là việc tìm kiếm trên đống dữ liệu mà bạn đã index. Bạn có thể tham khảo các link ở cuối bài, tất nhiên là hãy tìm đến chúng bằng cách đọc qua hết bài này.


PHP

Công nghệ mà tôi chọn cho project của mình là PHP, và tất nhiên phiên bản Lucene đầu tiên mà tôi thử nghiệm là phiên bản trên PHP. PHP Lucene là một phần của Zend Framework, gói Zend_Search_Lucene, đây là một bản port thuần PHP. Tôi hơi lo về performance của nó, bởi ai cũng biết PHP không được sinh ra để giải quyết các công việc nặng về logic. Nhưng mọi thứ không làm tôi thất vọng. Tôi thử index bộ manual của Zend Framework, nặng 40 MB, khoảng trên 3000 file HTML, tốn khoảng 5 phút. Chưa kể là trong lúc thử nghiệm, tôi còn nghe nhạc bằng Windows Media Player, viết tài liệu bằng Open Office Writer. Phần search cũng rất khá, mất trung bình 0.5 giây cho việc tìm kiếm từ khóa “Zend” trong đống dữ liệu trên, trả về hơn 1000 kết quả. Tuy nhiên một khuyết điểm rất lớn của Zend_Search_Lucene khiến tôi không thể sử dụng được nó là không hỗ trợ đầy đủ UTF-8. Dữ liệu bằng tiếng Việt bị hỏng khi index và không trả lại kết quả gì khi search,  chưa kể còn sinh ra cả loạt lỗi Notice từ iconv(). Ngoài ra, PHP Lucene còn chưa hỗ trợ một số tính năng có ở bản Java Lucene như sort chẳng hạn.

Java

Những thiếu sót trên khiến tôi phải quay qua Java Lucene, mặc dù tôi chưa bao giờ làm việc với Java (nhưng trong nhóm tôi có người làm Java). Dự định của tôi là bắt cầu PHP và Java để chạy Java Lucene. Nhưng ngoài PHP/Java bridge nằm trong sản phẩm thương mại Zend Platform ra thì hai giải pháp còn lại đề không họat động được bất chấp các nỗ lực của tôi. Ý tưởng sử dụng Java Lucene phá sản, nhưng tôi khám phá ra Solr, một search server dựa trên Java Lucene. Solr chạy ở trên một server riêng với Tomcat, các ứng dụng client sẽ giao tiếp với nó qua web service. Tôi mất một buổi chiều để cài Tomcat lần đầu tiên trong đời, sau đó deploy Solr. Nhưng sau đó tôi phát ra sự thật phũ phàng rằng Solr chỉ hỗ trợ một index trên mỗi application. Tôi có thể cấu hình để chạy nhiều ứng dụng Solr trên cùng một server, nhưng như thế sẽ ngốn rất nhiều tài nguyên. Vậy là phá sản rồi Solr ơi !

C#

Sau khi bỏ Java lại sau lưng, tôi nghĩ đến Lucene.NET (viết bằng C#). Tất nhiên tôi sẽ không sử dụng server Windows. Giải pháp duy nhất là Mono, nhưng tôi không dám phiêu lưu với một công nghệ mà chưa ai trong nhóm của tôi từng làm việc với nó. Bỏ qua .NET !

Ruby

Giải pháp tiếp theo của tôi là Ferret, phiên bản Lucene của Ruby. Ấn tượng đầu tiên là hệ thống API của Ferret khác hoàn toàn với bản Java Lucene gốc. Ý tưởng về một ứng dụng có cả PHP và Rails cũng không đến nỗi tồi. Nhưng giống như Zend_Search_Lucene, Ferret vẫn fail với Unicode, chưa kể nó còn gặp một số vấn đề về performance. Ferret đang được viết lại với C, Ruby chỉ là bề mặt, nhưng phiên bản C-Ferret vẫn chưa ổn định. Tạm biệt Ferret !

C++ (PHP Extension)

Tôi bắt đầu thấy bối rối, bởi vì gần như là hết cách rồi. Ý tưởng port CLucene (C++ Lucene) thành một PHP extension xem ra hơi phiêu lưu và không thực tiễn nếu xét về thời gian. Thực ra đã có một gói PECL để chạy CLucene với PHP, nhưng nó không đảm bảo vì thậm chí còn không có cả tài liệu.

Quay lại với PHP

Thế là tôi quyết định quay lại và nhúng tay vào Zend_Search_Lucene. Thật may là vấn đề UTF-8 đã được giải quyết một cách tạm thời. Giải pháp tạm của tôi như sau: Xét thấy dữ liệu text bằng tiếng Việt chủ yếu là gồm các ký tự Latin, tất cả nằm trong phạm vi của Latin-1 (ISO-8859-1) cho nên tôi quyết định thay iconv() mà nhóm phát triển Zend Framework sử dụng bằng hàm utf8_encode(). Tất nhiên tôi sẽ viết một lớp riêng để extend lại các lớp mà tôi cần thay đổi, sửa thẳng vào code là không khôn ngoan. Tôi hiện đang khá hạnh phúc với giải pháp này, trong khi chờ đợi một lời hứa “full support UTF-8” của Zend thành hiện thực.

Tuy nhiên, tôi nghĩ rằng ý tưởng biến C++ Lucene thành một extension còn hay hơn nhiều. Lúc đó khỏi phải lo về perfomance, vì ứng dụng search của tôi sẽ chạy nhanh và nhẹ hơn 20 lần ! 

 Links:

  1. Zend_Search_Lucene: http://framework.zend.com/manual/en/zend.search.html
  2. Java Lucene: http://lucene.apache.org/
  3. Solr: http://lucene.apache.org/solr/
  4. Ferret: http://ferret.davebalmain.com/trac/
  5. Lucene.NET: http://www.dotlucene.net/
  6. CLucene: http://clucene.sourceforge.net/

About this entry