/ / Codeigniter / Comments (6)

Tích hợp Zend_Search_Lucene kết hợp Jquery Autocomplete vào Codeigniter Framework

Vấn đề tìm kiếm dữ liệu luôn là 1 vấn đề được mọi người đặc biệt quan tâm.Chắc các bạn đã quen thuộc với cách tìm kiếm dữ liệu thông thường,Thời gian đầu mới nghiên cứu thì mình chỉ sử dụng full text search.Nhưng khi vào làm thực tế 1 vấn đề đặt ra khi tìm kiếm dữ liệu khá nhiều và cần sự chính xác thì full text search không đáp ứng được và thư viện Zend_Search_Lucene là phương án mình chọn.
Zend_Search_Lucene là 1 thư viện trong bộ thư viện của Zend framework,hôm nay mình sẽ hướng dẫn cho các bạn có thể tích hợp thư viện này vào CodeIgniter.Và mình rất thích CodeIgniter ở chỗ đó chính là rất dễ tích hợp các thư viện khác vào dự án.
– Trong bài này mình chỉ hướng dẫn cách tích hợp và sử dụng,còn các bạn muốn hiểu sâu hơn về các phương thức trong thư viện này thì các bạn tìm hiểu thêm nhé.VÍ dụ như các từ khóa create,open,find,addField,getFieldNames….
– Trước khi vào bài này thì chắc chắn các bạn phải biết 1 chút về CodeIgniter rồi nhé,các bạn có thể tham khảo các bài viết liên quan để có thể tìm hiểu sang bài này:

  1. Tổng quan về CodeIgniter framework
  2. Controller và URLs trong CodeIgniter framework
  3. Helpers và Libraries trong CodeIgniter

Các bước tích hợp thư viện Zend_Search_Lucene vào Codeigniter Framework

Bước 1 :
+Download thư viện Zend_Search_Lucene của Zend.Các bạn chú ý là chỉ download thư viện search và file Exception.php mà mình cần thôi nhé vì thư viện Zend khá nặng.Sau khi download về đặt trong thư mục library :

—library :
|—-search/
|—-Exception.php

+Các bạn lưu ý việc nữa là cần thay đổi tất cả đường dẫn require tất cả các file trong thư viện Zend_Search_Lucene nhé,không thì CI sẽ không gọi được các file đó đâu.(Không biết có cách nào khác k thì mình chưa tìm ra)
Bước 2 :
+Tạo thư mục để chứa data ngang hàng với index.php :

— search/index_search

Bước 3 :
+ Tạo thư viện Zend search trong thư mục library với nội dung:

—library :
|—-zend_search.php

<?php
class Zend_search
{
    var $CI;
    function __construct($class = NULL)
    {
        $this->CI =& get_instance();
    }
    /**
     *
     * Ket noi den data index
     */
    public function _index_connect()
    {
        // Tai thu vien Zend_Search_Lucene
        require_once APPPATH.'libraries/Zend/Search/Lucene.php';

        // Gọi tới path luu data index
        $data = './search/lucene_index';

        // Ket noi den data index
        try
        {
            $index = Zend_Search_Lucene::open($data);
                        //Mỡ thư mục chứa các tập tin search
        }
        catch (Exception $e)
        {
            $index = Zend_Search_Lucene::create($data);
                        //Tạo các tập tin search
        }

        // Gan kieu du lieu Utf8 khong phan biet chu hoa va chu thuong
        Zend_Search_Lucene_Analysis_Analyzer::setDefault(
            new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8_CaseInsensitive()
        );

        return $index;
    }

    /*create index document*/
    public function create_index(){
        $this->CI->load->Model('Mproduct');
        $arr_data = array() ;
        $index = $this->_index_connect();

        $input['where'] = array('active'=>1);
        $arr_data = $this->CI->Mproduct->get_list($input);
                //$arr_data chưa tất cả các dữ liệu sản phẩm
        foreach($arr_data as $pro) {
        //create an cache index doc
            $doc = new Zend_Search_Lucene_Document();
            $doc->addField(Zend_Search_Lucene_Field::Keyword('idpro', $pro['id']));
            $doc->addField(Zend_Search_Lucene_Field::Keyword('catalog', $pro['catalog']));
            $doc->addField(Zend_Search_Lucene_Field::text('name', $pro['name'], 'UTF-8'));
            $doc->addField(Zend_Search_Lucene_Field::text('key', $pro['key'], 'UTF-8'));
            $doc->addField(Zend_Search_Lucene_Field::text('key_en', convert_vi_to_en($pro['key']), 'UTF-8'));
            $doc->addField(Zend_Search_Lucene_Field::text('name_en', convert_vi_to_en($pro['name']), 'UTF-8'));
            $index->addDocument($doc);
        }
        $index->commit();
        $index->optimize();
        echo $index->count().' Documents indexed.';
    }

    /*end create index document*/

    /*save document*/
     function save_item($pro = null,$options = null){
       $index = $this->_index_connect();
       if($options['task']=='add'){
          $doc = new Zend_Search_Lucene_Document();
             $doc->addField(Zend_Search_Lucene_Field::Keyword('idpro', $pro['idpro']));
            $doc->addField(Zend_Search_Lucene_Field::Keyword('catalog', $pro['catalog']));
            $doc->addField(Zend_Search_Lucene_Field::text('name', $pro['name'], 'UTF-8'));
            $doc->addField(Zend_Search_Lucene_Field::text('key', $pro['key'], 'UTF-8'));
            $doc->addField(Zend_Search_Lucene_Field::text('key_en', $pro['key_en'], 'UTF-8'));
            $doc->addField(Zend_Search_Lucene_Field::text('name_en', $pro['name_en'], 'UTF-8'));
          $index->addDocument($doc);
          $index->commit();
          $index->optimize();
      }

      if($options['task']=='edit'){
          $hits = $index->find('idpro:'.$pro['idpro']);
          foreach ($hits as $hit) {
             $index->delete($hit->id);
          }

         $doc = new Zend_Search_Lucene_Document();

         $doc->addField(Zend_Search_Lucene_Field::Keyword('idpro', $pro['idpro']));
            $doc->addField(Zend_Search_Lucene_Field::Keyword('catalog', $pro['catalog']));
            $doc->addField(Zend_Search_Lucene_Field::text('name', $pro['name'], 'UTF-8'));
            $doc->addField(Zend_Search_Lucene_Field::text('key', $pro['key'], 'UTF-8'));
            $doc->addField(Zend_Search_Lucene_Field::text('key_en', $pro['key_en'], 'UTF-8'));
            $doc->addField(Zend_Search_Lucene_Field::text('name_en', $pro['name_en'], 'UTF-8'));

          $index->addDocument($doc);
          $index->commit();
          $index->optimize();
       }

       if($options['task']=='delete'){
          $hits = $index->find('idpro:'.$pro['idpro']);
          foreach ($hits as $hit) {
            $index->delete($hit->id);
          }
       }
   }
   /*end save document*/
}

+ Ở đây mình tìm kiếm theo tên sản phẩm (name),theo danh mục sản phẩm (catalog),theo từ khóa (key).Vì Zend_Search_Lucene không hỗ trợ tìm kiếm theo tiếng Việt lên mình tạo 2 trường có dấu và không dấu,trường không dấu này mình sử dụng chuyển đổi tiếng việt có dấu về không dấu thông qua 1 hàm tự xây dựng convert_vi_to_en với nội dung sau:

    /**
	 * Chuyen tieng viet co dau sang khong dau
	*/
	function convert_vi_to_en($str)
	{
		$characters = array(
			'/à|á|ạ|ả|ã|â|ầ|ấ|ậ|ẩ|ẫ|ă|ằ|ắ|ặ|ẳ|ẵ/' => 'a',
			'/è|é|ẹ|ẻ|ẽ|ê|ề|ế|ệ|ể|ễ/' => 'e',
			'/ì|í|ị|ỉ|ĩ/' => 'i',
			'/ò|ó|ọ|ỏ|õ|ô|ồ|ố|ộ|ổ|ỗ|ơ|ờ|ớ|ợ|ở|ỡ/' => 'o',
			'/ù|ú|ụ|ủ|ũ|ư|ừ|ứ|ự|ử|ữ/' => 'u',
			'/ỳ|ý|ỵ|ỷ|ỹ/' => 'y',
			'/đ/' => 'd',
			'/À|Á|Ạ|Ả|Ã|Â|Ầ|Ấ|Ậ|Ẩ|Ẫ|Ă|Ằ|Ắ|Ặ|Ẳ|Ẵ/' => 'A',
			'/È|É|Ẹ|Ẻ|Ẽ|Ê|Ề|Ế|Ệ|Ể|Ễ/' => 'E',
			'/Ì|Í|Ị|Ỉ|Ĩ/' => 'I',
			'/Ò|Ó|Ọ|Ỏ|Õ|Ô|Ồ|Ố|Ộ|Ổ|Ỗ|Ơ|Ờ|Ớ|Ợ|Ở|Ỡ/' => 'O',
			'/Ù|Ú|Ụ|Ủ|Ũ|Ư|Ừ|Ứ|Ự|Ử|Ữ/' => 'U',
			'/Ỳ|Ý|Ỵ|Ỷ|Ỹ/' => 'Y',
			'/Đ/' => 'D',
		);

		return preg_replace(array_keys($characters), array_values($characters), $str);
	}

+ Theo mình hiểu các trường thông tin dạng text như content hay name dùng như từ khóa tìm kiếm thì các bạn lưu dưới dạng Zend_Search_Lucene_Field::text
Bước 4:
+ Khi chúng ta sử dụng chức năng thêm ,sửa,xóa sản phẩm thì cũng phải thực hiện các chức năng đó trên file data search.
+ Tại Controller Product ta xây dựng các phương thức sau :

public function add(){
......
//sau khi thêm sản phẩm thực hiện index sản phẩm đó để  tìm kiếm
         $id = mysql_insert_id();//lấy id của sản phẩ vừa được add vào
         /*Zend Search*/
         $pro = array(
                'idpro'    => $id,
                'name'     => $this->input->post('name'),
                'name_en'  => convert_vi_to_en($this->input->post('name')),
                'catalog'  => $data['catalog'],
                'key'      => $data['key'],
                'key_en'   => convert_vi_to_en($data['key']),
        );
        //print_r($pro);die();
        $this->zend_search->save_item($pro,$options=array('task'=>'add'));
}

public function update($id){
.......
//Khi cập nhật sản phẩm ta sẽ thực hiện cập nhật document có id_pro tương ứng
// Các thức hoạt động như sau : sẽ xóa document có id_pro tương ứng sau đó mới index dữ liệu mới vào
       $pro = array(
              'idpro'    => $id,
              'name'     => $this->input->post('name'),
              'name_en'  => convert_vi_to_en($this->input->post('name')),
              'catalog'  => $data['catalog'],
              'key'      => $data['key'],
              'key_en'   => convert_vi_to_en($data['key']),
           );
      $this->zend_search->save_item($pro,$options=array('task'=>'edit'));
}

public function delete($idProduct){
     //thực hiện xóa document có id_pro tương ứng
     $pro['idpro'] = $idProduct;
     $this->zend_search->save_item($pro,$options=array('task'=>'delete'));
}

Bước 5:
+ Tạo 1 controller search :

 <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Search extends CI_Controller{
    public function __construct(){
        parent::__construct();

        $this->data['controller'] = __CLASS__;
        $this->load->Model('mproduct');
        $this->load->library("zend_search");
    }
    public function search_item(){
       if(isset($_GET['term'])){
               $index = $this->zend_search->_index_connect();
            // Set limit 100
            Zend_Search_Lucene::setResultSetLimit(100);
            // Gan kieu du lieu tim kiem
            Zend_Search_Lucene_Search_QueryParser::setDefaultEncoding('UTF-8');
            // Thuc hien tim kiem
            $key = $this->input->get('term');
            $query = 'name: '.$key.' OR name_en: '.$key.' OR key:'.$key.' OR key_en:'.$key;

            $hits = $index->find($query);
            //$hits là kết quả sau khi tìm kiếm
            $result = array();
            foreach ($hits as $i => $hit)
            {
                $row = new stdClass();
                        $document = $hit->getDocument();
                foreach ($document->getFieldNames() as $f)
                {
                    $row->{$f} = $document->getFieldValue($f);
                }
                $result[] = $row;
            }
            //print_r($result);
            $json = array();
            foreach ($result as $row)
            {
                $item = array();
                $item['id'] = $row->idpro;
                $item['label'] = $row->name;
                $item['value'] = $row->name;
                $json[] = $item;
            }
            $output = json_encode($json);
            //dữ liệu trả về dạng Json để sử dụng trong Jquery Autocomplete
            echo $output ;
      }else{
          redirect();
      }
    }
}

Các bạn cần chú ý trong Jquery Autocomplete sẽ sử dụng dữ liệu dạng Json lên các bạn cần trả dữ liệu về dạng Json

Bước 6
+ Tại View : Các bạn tải Jquery Autocomplete về nhé và sử dụng như sau :

<script type="text/javascript">
$(function() {
    $( "#Inputsearch" ).autocomplete({
        source: "<?php echo base_url('search/search_item')?>",

    });
});
</script>
//Nạp thư viện Jquery Autocomplete
<link type="text/css" href="<?php echo public_url('default/autocomplete/css/smoothness/jquery-ui-1.8.16.custom.css')?>" rel="stylesheet" />
<script type="text/javascript" src="<?php echo public_url('default/autocomplete/jquery-ui-1.8.16.custom.min.js')?>"></script>

 <form  id="search" method="get" action="<?php echo base_url('search.html')?>">
    <input type="text" maxlength="100" autocomplete="off" placeholder="Từ khóa tìm kiếm" value="" name="searchInput"  id="Inputsearch">
<button id='submit' class="sel-search-button">Search</button>
</form>

Với code phía trên các bạn thấy chúng ta đang khai báo #Inputsearch sẽ thực hiện Autocomplete,và source nó là cấu hình đường dẫn tìm kiếm dữ liệu và trả kết quả về dưới dạng Json. Các bạn có thể tìm hiểu thêm về thư viện này tại đây
Và kết quả sẽ hiển thị như sau:

Tích hợp Zend_Search_Lucene kết hợp Jquery Autocomplete vào Codeigniter Framework


07/09/2014
Written by nobitacnt

Trong bài viết không tránh khỏi những câu từ chưa chính xác,mong nhận được sự góp ý để website hoàn thiện hơn.Nếu thấy bài viết có ích với bạn hãy like và share để ủng hộ nhé :D.

Bài viết chùng chuyên mục

6 Comments

  1. Mì Tôm says:
     /  Reply

    Cám ơn ad nhé. đúng cái mình cần. dễ hiểu quá 😀 😀 😀 😀

    • nobitacnt says:
       /  Reply

      :D,cám ơn Mì Tôm đã quan tâm

  2. Manhj says:
     /  Reply

    Admin có demo phần này không ?
    Mình chưa biết về Zend nên khi tích hợp vào CI thì chưa hiểu lắm.
    Phần thay đổi tất cả đường dẫn require tất cả các file là đổi thành đường dẫn như thế nào ?
    Mình thấy có phần model mà chưa rõ trong model khai báo gì cho hợp lý.

    Admin demo nhỏ giúp mình copy, chỉnh sửa chi tiết ntn nhé.
    Mình thấy bản Zend 2.xx thì k có folder Search nữa ấy.

    Cảm ơn admin

    • nobitacnt says:
       /  Reply

      Phần trên mình hướng dẫn khá chi tiết, gần như bạn chỉ cần copy và làm theo hướng dẫn thôi, thay đổi lại các biến cho phù hợp với csdl của bạn, còn demo thì nó cũng chỉ là đoạn nhập từ khóa tìm kiếm vào o input thôi.

      • Mạnh says:
         /  Reply

        nobitacnt có thể đính kèm thêm file thư viện zend không ?
        Mình tìm thư viện của zend mà k biết nên lấy file nào, có đúng k ấy.
        Nếu được bạn đính kèm vào bài viết để m.ng có thể tìm thấy đơn giản hơn.

        Thanks bạn rất nhiều !

Gửi bình luận

Giới thiệu

Mình tạo ra blog này với mong muốn chia sẻ và học hỏi kinh nghiệm trong quá trình thiết kế website. Website đang trong quá trình phát triển chân thành cảm ơn mọi sự góp ý của các bạn để làm cho website ngày càng hoàn thiên.

DMCA.com Protection Status
Theo dõi qua Email

Tổng hợp các bài viết về

Hoc php - CodeIgniter Framework - Laravel Framework - PHP va MYSQL