AdityaDees: search engine

Hot

https://publishers.chitika.com/

Contact us for advertising.
Showing posts with label search engine. Show all posts
Showing posts with label search engine. Show all posts

29 April 2010

Compile Sphinx indexing engine di Mac OSX 10.6.3

17:16 0
Cari solusi indexing database standalone yang handal? Salah satu solusinya adalah Sphinx. Sphinx adalah engine pengindeksan full-text yang didesain untuk terintegrasi dengan baik ke RDBMS-RDBMS macem MySQL dan PostgreSQL, dan yang asiknya laginya Sphinx sudah menyediakan API ke bahasa-bahasa scripting populer macem PHP, Python, Perl dan Ruby.


Karena saya develop aplikasi pake bahasa skripting PHP, maka Sphinx merupakan solusi yang pas untuk saya. Salah satu fitur yang bikin saya ngiler adalah statement berikut ini:



"high search speed (avg query is under 0.1 sec on 2-4 GB text collections)"

Wuiidddiihhh kalo dibandingin sama indexing native mysql, 100 ribu records yang besarnya sekitar 30MB aje ude empot-empotan!!! Statement berikutnya juga bikin ileran



"high scalability (upto 100 GB of text, upto 100 M documents on a single CPU)"

Saat tulisan ini dibuat, saya develop aplikasi web pake Macbook Pro, OS Snow Leopard 10.6.3, dan karena saya males compile-compile Apache, MySQL dan PHP (kecuali di OS GNU/Linux entah kenapa kurang apdol rasanya kalo ga di-compile sendiri heheheheee *kabboorr*), jadilah saya pake XAMPP for Mac OSX versi 1.7.2.


Karena binary Sphinx kage ade buat Mac OSX, cuman ade buat "Mikocok Winslow", maka itu berarti kite harus compile sendiri Sphinx. ALHAMDULILLAH WA SYUKURILLAH! OSX udah nyedian Xcode yang didalemnya udah ada semua tool development UNIX macem gcc, g++, make, automake, autoconf, you name it lah! GRATIS lagi! *Getokin Apple kalo sampe paket XCode dibikin berbayar*. ALHAMDULILLAH lagi, karena Mac OSX basisnya UNIX juga (Darwin+FreeBSD), maka console dengan shell prompt Bash yang kesohor itupun ude ade by default di OSX *ffiuuuuhhhhh, can't live without those consoles*. ALHAMDULILLAH lagi! struktur direktori Mac OSX yang kaga jauh beda sama UNIX atau GNU/Linux!


Jadilah saya "iseng-iseng berhadiah" compile Sphinx di Macbook Pro saya. Yang pasti sebelum mulai compile Sphinx, download dan install dahulu library-library berikut ini (beserta dengan header-header developmentnya!! kudu, wajib!!):



  1. Source code terbaru Sphinx

  2. Source code libstemmer

  3. Source code dan file-file header MySQL kalo kita mau integrasikan Sphinx dengan MySQL

  4. Source code dan file-file header PostgreSQL kalo kita mau integrasikan Sphinx dengan PostgreSQL

  5. Bagi yang menggunakan XAMPP bisa lebih mudah, download paket XAMPP-Dev yang sesuai dengan versi yang kita pake


Proses instalasinya kira-kira begini:



  1. Buka aplikasi "Terminal", kalo belom tau coba cari di /Applications/Utilities/

  2. Ekstrak file distribusi Sphinx pake perintah:
    tar xvf sphinx-0.9.9.tar.gz

  3. Ekstrak file distribusi libstemmer dan kopikan folder ekstraksi libstemmer ke dalam folder source Sphinx yang baru saja kita ekstrak pake perintah:
    cp -r ./libstemmer_c sphinx-0.9.9

  4. Masuk ke direktori hasil ekstraksi pake perintah:
    cd sphinx-0.9.9


  5. Karena saya pake XAMPP Mac OSX perintah configure saya seperti ini:

    Dicarve@Macbook sphinx-0.9.9$ CFLAGS="-O -arch i386" CXXFLAGS="-O -arch i386 -I/Applications/XAMPP/xamppfiles/include/ -I/Applications/XAMPP/xamppfiles/include/mysql" LDFLAGS="-arch i386 -L/Applications/XAMPP/xamppfiles/lib" ./configure --prefix=/usr/local/ --with-mysql -with-libstemmer --with-mysql-includes=/Applications/XAMPP/xamppfiles/include/mysql --with-mysql-libs=/Applications/XAMPP/xamppfiles/lib/mysql

    Saya sempet agak-agak stress karena diawal-awal proses kompilasi gagal melulu! setelah baca-baca keliling Internet dan baca disini, ternyata sphinx-nye harus di-compile di mode 32 bit! *karena by default gcc di Mac OSX compile di mode 64 bit*






  6. Apabila proses konfigurasi berjalan lancar tanpa masalah, maka lanjutkan dengan perintah berikut secara berurutan:

    $ make

    $ sudo make install



Horreee Sphinx berhasil diinstall!!!! Yiiihhuuu!!! Selanjutnya tinggal konfigurasi Sphinx biar bisa "bicara" sama MySQL atau PostgreSQL, selamat mencoba, dan jangan lupa baca dokumentasi sphinx di website resminya, RTFM!
Read More

01 September 2008

Bikin Search Engine FullText dengan Zend Search Lucene - Searching/Pencarian

09:50 0


Pada posting sebelumnya saya sudah sedikit memaparkan bagaimana cara membuat dan menambahkan indeks database dokumen fulltext dengan menggunakan Zend Search Lucene. Sekarang saya akan sedikit memaparkan bagaimana cara untuk melakukan pencarian ke dalam indeks yang telah dibuat dengan menggunakan Zend Search Lucene.




Untuk melakukan pencarian, Zend Search Lucene menyediakan beberapa metode, tetapi yang paling simpel adalah menggunakan metode find(), dari objek INDEX (instance fungsi factory Zend_Search_Lucene::open). Metode find() mempunyai 2 argumen, argumen pertama adalah kata kunci/keyword yang ingin kita query, dan argumen kedua adalah default field metadata yang akan di-coba temukan oleh indexer. HATI-HATI DENGAN QUERY WILDCARD (*)! Listing programnya kira-kira seperti ini :


<?php
// include paging class
require 'lib/simbio_paging.inc.php';
require 'lib/utils.inc.php';
// get keywords
$keywords = trim($_GET['keywords']);
if ($keywords AND $keywords != '*') {
// search the index
$matches = $index->find($keywords, 'title');
if ($num_matches = count($matches)) {
// slice the array
if ($num_matches > $config['recs_each_page']) {
// get page number from http get var
$page = 1;
if (isset($_GET['page']) AND $_GET['page'] > 1) {
$page = (integer)$_GET['page'];
}
// count the row offset
$remove_offset = $config['recs_each_page'];
if ($page > 1) {
$remove_offset = ($page*$config['recs_each_page']);
// slice from first element of array
array_splice($matches, 0, ($remove_offset-$config['recs_each_page']));
}
// slice the rest elements of array
array_splice($matches, $config['recs_each_page']);
}
echo 'Found <b>'.$num_matches.'</b> document matches your keyword : <hr size="1" />'."\n";
foreach ($matches as $doc) {
echo '<div style="clear: both: margin: 5px; margin-bottom: 20px;">'
.'<div style="font-weight: bold;">'.$doc->title.'</div>'
.'<div style="margin-left: 10px;">'.$doc->author.'</div>'
.'<div style="margin-left: 10px;"><a href="?mod=search&action=action&docID='.urlencode($doc->checksum).'" target="_blank">'.basename($doc->file_name).'</a></div>'
.'</div>';
}
}
// paging
if ($num_matches > $config['recs_each_page']) {
echo simbio_paging::paging($num_matches, $config['recs_each_page'], 10);
}
} else {
echo utils::showError('No Keywords Entered!');
}
?>







Yang agak rumit mungkin adalah paging search resultnya. Zend Search Lucene kaga nyediain tuh yang namanya klausa "LIMIT", "OFFSET", "TOP" kaya di RDBMS-RDBMS populer, agak-agak tricky si caranya, tapi "it works". Ini saya langsung kasih juga script pagingnya yang saya ambil dari library development PHP, SIMBIO 2 yang selalu saya gunakan dalam mengembangkan aplikasi.


<?php
/**
* simbio_paging
* Paging Generator class
*
* Copyright (C) 2007,2008 AdityaDees (adityadees@yahoo.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/

 
class simbio_paging
{
/**
* Static Method to print out the paging list
*
* @param integer $int_all_recs_num
* @param integer $int_recs_each_page
* @param integer $int_pages_each_set
* @param string $str_fragment
* @param string $str_target_frame
* @return string
*/

public static function paging($int_all_recs_num, $int_recs_each_page, $int_pages_each_set = 10, $str_fragment = '', $str_target_frame = '_self')
{
// check for wrong arguments
if ($int_recs_each_page > $int_all_recs_num) {
return;
}
 
// total number of pages
$_num_page_total = ceil($int_all_recs_num/$int_recs_each_page);
 
if ($_num_page_total < 2) {
return;
}
 
// total number of pager set
$_pager_set_num = ceil($_num_page_total/$int_pages_each_set);
 
// check the current page number
if (isset($_GET['page']) AND $_GET['page'] > 1) {
$_page = (integer)$_GET['page'];
} else {$_page = 1;}
 
// check the query string
if (isset($_SERVER['QUERY_STRING']) AND !empty($_SERVER['QUERY_STRING'])) {
parse_str($_SERVER['QUERY_STRING'], $arr_query_var);
// rebuild query str without "page" var
$_query_str_page = '';
foreach ($arr_query_var as $varname => $varvalue) {
$varvalue = urlencode($varvalue);
if ($varname != 'page') {
$_query_str_page .= $varname.'='.$varvalue.'&';
}
}
// append "page" var at the end
$_query_str_page .= 'page=';
// create full URL
$_current_page = $_SERVER['PHP_SELF'].'?'.$_query_str_page;
} else {
$_current_page = $_SERVER['PHP_SELF'].'?page=';
}
 
// target frame
$str_target_frame = 'target="'.$str_target_frame.'"';
 
// init the return string
$_buffer = '<span class="pagingList">';
$_stopper = 1;
 
// count the offset of paging
if (($_page > 5) AND ($_page%5 == 1)) {
$_lowest = $_page-5;
if ($_page == $_lowest) {
$_pager_offset = $_lowest;
} else {
$_pager_offset = $_page;
}
} else if (($_page > 5) AND (($_page*2)%5 == 0)) {
$_lowest = $_page-5;
$_pager_offset = $_lowest+1;
} else if (($_page > 5) AND ($_page%5 > 1)) {
$_rest = $_page%5;
$_pager_offset = $_page-($_rest-1);
} else {
$_pager_offset = 1;
}
 
// Previous page link
if (defined('lang_sys_common_paging_first')) {
$_first = lang_sys_common_paging_first;
} else {
$_first = 'First Page';
}
 
if (defined('lang_sys_common_paging_prev')) {
$_prev = lang_sys_common_paging_prev;
} else {
$_prev = 'Previous Page';
}
 
if ($_page > 1) {
$_buffer .= ' &nbsp;';
$_buffer .= '<a href="'.$_current_page.(1).$str_fragment.'" '.$str_target_frame.'>'.$_first.'</a>&nbsp; '."\n";
$_buffer .= ' &nbsp;';
$_buffer .= '<a href="'.$_current_page.($_page-1).$str_fragment.'" '.$str_target_frame.'>'.$_prev.'</a>&nbsp; '."\n";
}
 
for ($p = $_pager_offset; ($p <= $_num_page_total) AND ($_stopper < $int_pages_each_set+1); $p++) {
if ($p == $_page) {
$_buffer .= ' &nbsp;<b>'.$p.'</b>&nbsp; '."\n";
} else {
$_buffer .= ' &nbsp;';
$_buffer .= '<a href="'.$_current_page.$p.$str_fragment.'" '.$str_target_frame.'>'.$p.'</a>&nbsp; '."\n";
}
 
$_stopper++;
}
 
// Next page link
if (defined('lang_sys_common_paging_next')) {
$_next = lang_sys_common_paging_next;
} else {
$_next = 'Next';
}
 
if (($_pager_offset != $_num_page_total-4) AND ($_page != $_num_page_total)) {
$_buffer .= ' &nbsp;';
$_buffer .= '<a href="'.$_current_page.($_page+1).$str_fragment.'" '.$str_target_frame.'>'.$_next.'</a>&nbsp; '."\n";
}
 
// Last page link
if (defined('lang_sys_common_paging_last')) {
$_last = lang_sys_common_paging_last;
} else {
$_last = 'Last Page';
}
 
if ($_page < $_num_page_total) {
$_buffer .= ' &nbsp;';
$_buffer .= '<a href="'.$_current_page.($_num_page_total).$str_fragment.'" '.$str_target_frame.'>'.$_last.'</a>&nbsp; '."\n";
}
 
$_buffer .= '</span>';
 
return $_buffer;
}
}
?>





Nah begitulah kira-kira sedikit mengenai penggunaan Zend Search Lucene untuk membuat indeks dokumen fulltext. Dari sini kita bisa saja kembangkan untuk membuat search engine kecil-kecilan yang bermanfaat buat kita, contohnya saya meng-indeks manual PHP offline HTML agar saya bisa dengan cepat menemukan topik yang saya ingin baca.




Untuk peng-indeksan skala besar (jumlah dokumen dalam ukuran giga atau tera), saya menyarankan untuk menggunakan engine-engine indexing yang sudah mumpuni seperti Lucene (java), Clucene (C++), Swish-e, Lemur, Terrier, Xapian dll. Semoga artikel ini bermanfaat untuk anda yang membacanya.

Read More

29 August 2008

Bikin Search Engine FullText dengan Zend Search Lucene

14:26 0


Zend Framework merupakan salah satu framework pengembangan aplikasi PHP yang canggih dan populer (ya iyaaalah yang buat developer di Zend, secara Zend yang buat engine pre-prosesor PHP). Framework ini tidak hanya menyediakan library-library yang memudahkan dalam pengembangan aplikasi yang modular dan kompleks, tetapi juga menyediakan fondasi pengembangan aplikasi model MVC (Model View Controller) yang sangat "sophisticated".




Salah satu library dari Zend Framework yang sangat bermanfaat untuk pengembangan mesin pencari/search engine adalah library Zend Search Lucene. Zend Search Lucene adalah porting dari Apache Lucene, engine Java untuk peng-indeksan dokumen full-text yang sangat canggih saat ini dan masih terus dikembangkan. Hebatnya, hasil index dari Zend Search Lucene bisa dipake juga oleh Lucene dan juga sebaliknya! Perlu diingat secara default Lucene dan turunannya hanya meng-indeks file-file teks biasa seperti HTML, XML, TXT dll. Untuk mengindeks file-file PDF, WORD, Excel, Powerpoint diperlukan eksternal parser yang berfungsi mengubah file-file dalam format tersebut ke dalam bentuk teks biasa. Kalo di platform Linux/UNIX untuk meng-indeks file WORD, Powerpoint dan Excel saya pake program command-line catdoc. Sedangkan untuk file-file PDF kita bisa menggunakan program xpdf untuk mem-parsing menjadi teks.




Sekarang kita langsung aja ke pratik-nya, bagaimana gunain Zend Search Lucene di program kita.
Langkah pertama pastinya ada menginstall terlebih dahulu Zend Framework. Download versi terbaru dari Zend Framework di website resmi-nya lalu ikuti instruksi install-nya yang bisa dilihat pada dokumentasi resmi-nya. Setelah kita ter-install dengan baik, maka kita sudah bisa menggunakan library Zend Search Lucene dengan menambahkan baris :


<?php require 'Zend/Search/Lucene.php'; ?>




pada skrip PHP kita. Kalau saya menempatkan file tersebut pada file konfigurasi global aplikasi yang pasti selalu ter-include di hampir semua skrip aplikasi. Contohnya seperti ini :


<?php
/**
* AdityaDees 2008
* ZLucene config file
*
*/

 
// Required Library
require 'Zend/Search/Lucene.php';
require 'lib/utils.inc.php';
 
ini_set('display_errors', false);
 
// Constant
define('INDEXES_DIR', 'indexes');
define('INDEXES_BASE_DIR', INDEXES_DIR.DIRECTORY_SEPARATOR.'index');
define('DOCS_DIR', 'docs');
define('DOCS_BASE_DIR', '.'.DIRECTORY_SEPARATOR.DOCS_DIR);
?>







Langkah selanjutnya adalah membuat yang namanya INDEX. INDEX mudahnya adalah database metadata dari semua keyword yang berada pada repository dokumen kita. Untuk membuat INDEX caranya seperti ini :




<?php
// check if the index is already available
try {
if (file_exists(INDEXES_BASE_DIR)) {
// open the index
$index = Zend_Search_Lucene::open(INDEXES_BASE_DIR);
} else {
// create the index
$index = Zend_Search_Lucene::create(INDEXES_BASE_DIR);
define('NEW_INDEX_CREATED', 'New Indexes Created at '.INDEXES_BASE_DIR);
}
// set search result limit
// Zend_Search_Lucene::setResultSetLimit(30);
// set default search field
Zend_Search_Lucene::setDefaultSearchField('content');
} catch (Zend_Search_Lucene_Exception $exc) {
define('ERROR_OPEN_CREATE_INDEXES', 'Failed to open or create indexes file with error : '.$exc->getMessage());
}
?>







Setelah berhasil membuat INDEX, maka instance/objek hasil dari fungsi factory Zend_Search_Lucene::open (variable $index), bisa kita lakukan untuk melakukan berbagai macam manipulasi INDEX, seperti pencarian, manipulasi field metadata INDEX, dsb. Sebagai mana halnya kita membuat database biasa, metadata dari INDEX harus kita tentukan field-fieldnya. Untuk memudah manipulasi field metadata di kemudian waktu, maka saya membuat definisi field dalam bentuk array yang fleksibel :


<?php
// metadata field definition
$config['md_field']['indexed'][] = 'title';
$config['md_field']['indexed'][] = 'author';
$config['md_field']['unindexed'][] = 'file_name';
$config['md_field']['unindexed'][] = 'file_mime_type';
$config['md_field']['unindexed'][] = 'file_size';
$config['md_field']['unindexed'][] = 'input_date';
$config['md_field']['unindexed'][] = 'last_update';
$config['md_field']['unindexed'][] = 'checksum';
$config['md_field']['unstored'][] = 'content';
 
// metadata ID for document delete/update purpose
$config['md_id_field'] = 'checksum';
$config['md_id_checksumed_field'] = 'file_name';
$config['md_field']['keyword'][] = $config['md_id_field'];
?>







Ada beberapa tipe field metadata yang harus kita kenal di Zend Search Lucene :


  1. Text

    Tipe field yang di-indeks, disimpan pada INDEX dan di-tokenize (dipecah-pecah per-kata). Sangat berguna untuk menyimpan data-data seperti Subjek/Topik dokumen, Pengarang dan Judul dokumen.

  2. Keyword

    Tipe field yang di-indeks, disimpan pada INDEX tetapi tidak di-tokenize. Berguna untuk menyimpan istilah yang mengandung lebih dari satu kata dan tidak terpisahkan.

  3. Unindexed

    Tipe field yang tidak di-indeks, tetapi tersimpan dalam INDEX dan bisa dimunculkan pada hasil pencarian.

  4. UnStored

    Tipe field yang di-indeks dan di-tokenize, tetapi tidak tersimpan dalam INDEX. Tipe field ini bisa digunakan untuk menyimpan indeks konten/isi dokumen yang besar.





Untuk memudahkan dalam melakukan proses peng-indeksan saya membuat sebuah kelas yang berfungsi sebagai wrapper proses peng-indeksan. Kelas ini dilengkapi metode-metode tambahan untuk melakukan peng-indeksan isi directory secara recursif. Untuk saat ini, kelas ini hanya bisa melakukan peng-indeksan pada dokumen-dokumen text biasa seperti HTML, XML dan TXT. Definisi kelasnya sebagai berikut :


<?php
/**
* AdityaDees 2008
* A Zend Search Lucene Indexer Wrapper
*
*/

 
class ZLucene_Indexer
{
const AUTO_COMMIT_AFTER_INDEX = 1;
private $zend_search_lucene = false;
private $indexed_file_type = array('html', 'htm', 'xml', 'txt');
private $recursive_index = false;
private $doc_id_field = 'checksum';
private $doc_id_checksumed_field = 'checksum';
protected $md_fields = array();
 
/**
* Class Constructor
*
* @param object $obj_zend_search_lucene
* @param array $array_md_fields
*/

public function __construct($obj_zend_search_lucene, $array_md_fields)
{
if (!$obj_zend_search_lucene instanceof Zend_Search_Lucene_Proxy) {
die('Please supply ZLucene_Indexer with valid Zend_Search_Lucene index instance');
}
$this->zend_search_lucene = $obj_zend_search_lucene;
$this->md_fields = $array_md_fields;
}
 
 
/**
* Method to set document ID field
*
* @param string $str_doc_id_field
* @param string $str_doc_id_checksumed_field
*/

public function setDocID($str_doc_id_field, $str_doc_id_checksumed_field)
{
$this->doc_id_field = $str_doc_id_field;
$this->doc_id_checksumed_field = $str_doc_id_checksumed_field;
}
 
 
/**
* Method to set recursive directory indexing for indexDirectory method
*
*/

public function setRecursiveIndex()
{
$this->recursive_index = true;
}
 
 
/**
* Method to add one document to index
*
* @param object $obj_zend_search_document
* @param array $array_field_data
* @param integer $int_zlucene_const
*/

public function indexDoc($obj_zend_search_document, $array_field_data, $int_zlucene_const = 0)
{
// delete document from indexes first
$deleted_term = new Zend_Search_Lucene_Index_Term($array_field_data[$this->doc_id_field], $this->doc_id_field);
$deleted = new Zend_Search_Lucene_Search_Query_Term($deleted_term);
$matches = $this->zend_search_lucene->find($deleted);
if ($matches) {
foreach ($matches as $doc) {
$this->zend_search_lucene->delete($doc->id);
// echo $doc->id.' deleted!<br />';
}
}
// iterate trough metadata fields
foreach ($this->md_fields as $field_type => $fields) {
foreach ($fields as $field) {
if ($field_type == 'indexed') {
if (isset($array_field_data[$field])) {
$obj_zend_search_document->addField(Zend_Search_Lucene_Field::Text($field, $array_field_data[$field]));
// echo $array_field_data[$field].' indexed!<br />';
}
} else if ($field_type == 'unindexed') {
if (isset($array_field_data[$field])) {
$obj_zend_search_document->addField(Zend_Search_Lucene_Field::UnIndexed($field, $array_field_data[$field]));
// echo $array_field_data[$field].' unindexed!<br />';
}
} else if ($field_type == 'unstored') {
if (isset($array_field_data[$field])) {
$obj_zend_search_document->addField(Zend_Search_Lucene_Field::UnStored($field, $array_field_data[$field]));
// echo $array_field_data[$field].' unstored!<br />';
}
} else {
if (isset($array_field_data[$field])) {
$obj_zend_search_document->addField(Zend_Search_Lucene_Field::Keyword($field, $array_field_data[$field]));
// echo $array_field_data[$field].' keyword stored!<br />';
}
}
}
}
// add to index
$this->zend_search_lucene->addDocument($obj_zend_search_document);
// commit index change
if ($int_zlucene_const === self::AUTO_COMMIT_AFTER_INDEX) {
$this->zend_search_lucene->commit();
}
}
 
 
/**
* Method to index directory content
*
* @param string $str_dir_path
* @param array $array_default_field_data
*/

public function indexDirectory($str_dir_path, $array_default_field_data)
{
// check if directory exists
if (!file_exists($str_dir_path)) {
echo 'Directory '.$str_dir_path.' not exists!'."\n";
return;
}
// open directory
if ($directory = opendir($str_dir_path)) {
// number of document indexed
$doc_count = 0;
// read directory content
while (false !== ($file = readdir($directory))) {
// ignore dots
if ($file != '.' AND $file != '..') {
// current file
$file_path = $str_dir_path.DIRECTORY_SEPARATOR.$file;
// check if the $file is file or directory
if (is_dir($file_path) AND $this->recursive_index) {
$doc_count += self::indexDirectory($file_path, $array_default_field_data);
} else {
preg_match('@\.(html|htm|txt|xml)$@i', $file, $file_ext);
if (!empty($file_ext[1]) AND in_array($file_ext[1], $this->indexed_file_type)) {
// reset title field value
$metadata['title'] = null;
// set default mimetype
$file_mime_type = 'text/plain';
// get file content
$content = file_get_contents($file_path);
// get value of HTML title tags
if ($file_ext[1] == 'html' OR $file_ext[1] == 'htm' OR $file_ext[1] == 'xml') {
preg_match('@<title>(.+)<\/title>@i', $content, $title);
$file_ext[1] = ($file_ext[1] == 'htm')?'html':$file_ext[1];
$file_mime_type = 'text/'.$file_ext[1];
$metadata['title'] = !empty($title[1])?trim($title[1]):null;
// echo $title[1].'<br />';
} else if ($file_ext[1] == 'doc' OR $file_ext[1] == 'rtf') {
 
}
// set filename as a title field value
if (!$metadata['title']) {
$uc_file_name = ucwords(str_replace(array('-', '_'), ' ', $file));
// replace last file name extension
$metadata['title'] = preg_replace('@\.[^\.]+$@i', '', $uc_file_name);
}
$metadata['content'] = strip_tags($content);
$metadata['author'] = 'adityadees@yahoo.com';
$metadata['file_name'] = $file_path;
$metadata['file_size'] = filesize($file_path);
$metadata['file_mime_type'] = $file_mime_type;
// create checksum as an ID
$metadata['checksum'] = md5($metadata[$this->doc_id_checksumed_field]);
self::indexDoc(new Zend_Search_Lucene_Document(), $metadata);
$doc_count++;
// echo $metadata['title'].' succesfully indexed!<br />';
}
}
}
}
// close directory handle
closedir($directory);
// commit index changes
$this->zend_search_lucene->commit();
// optimize the index
$this->zend_search_lucene->optimize();
return $doc_count;
} else {
die('Directory '.$str_dir_path.' is not readable. Please check directory permission!');
}
}
 
 
/**
* Method to parse Microsoft Word *.doc file with catdoc
*
* @param string $str_docfile_path
* @return string
*/

public function parseMSWord($str_docfile_path, $str_catdoc_path = '/usr/bin/catdoc')
{
if (!file_exists($str_docfile_path)) {
echo $str_docfile_path.' not found!'."<br />\n";
return null;
}
if (!file_exists($str_catdoc_path) OR !is_executable($str_catdoc_path)) {
echo $str_catdoc_path.' not found or not executable!'."<br />\n";
return null;
}
$outputs = array();
// execute catdoc
@exec($str_catdoc_path, $outputs, $status);
 
}
}
?>







Penggunaan kelas Zlucene_Indexer ini cukup mudah. Skrip untuk meng-indeks konten direktori /var/www/html/docs kira-kira seperti ini :



<?php
/**
* AdityaDees 2008
*
*/

 
// index directory content recursively
// set PHP script time limit
set_time_limit(0);
$start = microtime(true);
$dir_to_index = '/var/www/html/docs';
$ZLucene_Indexer = new ZLucene_Indexer($index, $config['md_field']);
// recursively index directory contents
$ZLucene_Indexer->setRecursiveIndex();
// set ID field
$ZLucene_Indexer->setDocID($config['md_id_field'], $config['md_id_checksumed_field']);
// array containing default metadata content
$doc_default_metadata= array();
// index directory contents
$num_indexed = $ZLucene_Indexer->indexDirectory($dir_to_index, $doc_default_metadata);
$end = microtime(true);
$index_time = $end-$start;
echo '<strong>'.$num_indexed.'</strong> documents indexed on <strong>'.$dir_to_index.'</strong> directory in '.$index_time.' seconds!'."\n";
?>







Sebagai catatan tambahan, Zend Search Lucene punya beberapa keterbatasan yaitu besar file INDEX maksimal hanya 2GB pada sistem operasi 32 Bit, proses peng-indeksan cenderung lambat terlebih apabila ukuran dan jumlah file besar (saya pernah mencoba mengindeks kurang lebih 11.000 dokumen HTML dan baru selesai dalam waktu setengah jam!).




Nah sekian dulu sampe disini pembahasan mengenai peng-indeksan dokumen full-text dengan menggunakan Zend Search Lucene. Pada posting blog yang akan datang saya akan membahas juga mengenai cara pencarian dokumen pada Zend Search Lucene.

Read More

https://payclick.com/

Contact us for advertising.