Using the Zend framework Lucene library
Adding a site search function
I know, only a few articles in, so I don’t really need a site search function. But you never know, I might actually keep writing (even if no-one is reading) and so I’ve been looking around for some solutions.
I’ve looked at a few, for example: Swish-e, and Sphider. Nothing really float my boat, until I had a look at the Zend Framework. It’s another MVC based PHP framework, though it looks a little heavier than CodeIgniter. The documentation is not as good either, but it did have a Lucene library.
I found a way of incorporating a Zend framework class as a CodeIgniter library here by Fred Wu. Nice work Fred, thanks.
As Fred suggests, copy the Zend folder from the framework library to application/libraries/ in your CodeIgniter installation. I discovered that I only needed the Zend/Search folder, and the Zend/Exception.php file.
Continuing Fred’s instructions, create a Zend.php library file with the code posted on his blog page. Now we can get started.
Create a directory for the index. In my example code I created a directory called application/search. Now we can create a controller called search.php that will contain some simple create, and search methods:
<?php class Search extends MY_Controller { function Search() { parent::MY_Controller(); $this->load->library('zend'); $this->zend->load('Zend/Search/Lucene'); } function create() { // This method should be authenticated, or removed once the index is created. // TODO: Some sort of site spidering process to add the entire site to the index. $index = Zend_Search_Lucene::create(APPPATH . 'search/index'); $doc = Zend_Search_Lucene_Document_Html::loadHTMLFile('http://www.andrewrowland.com'); $index->addDocument($doc); echo '<p>Index created</p>'; } function index() { // TODO: Create an index method that contains a search form. } function result() { // Hardcoded search result example. // TODO: Take a user search query, and expand the result summary $index = Zend_Search_Lucene::open(APPPATH . 'search/index'); $data['results'] = $index->find('andrew'); $this->load->view('search_result_view', $data); } } ?>I didn’t bother with the create index view, as all that is needed is a simple message explaining that the index is created. The search_result_view.php view will display the results:
<html> <head> <title>Search example</title> </head> <body> <ul> <?php foreach($results as $result):?> <li><?php echo $result->title;?></li> <?php endforeach;?> </ul> </body> </html>
As you can see, I’ve noted a few TODO’s. Might add a bit of jQuery action (because I’m worth it) in there to. Weekend coming up, so I’ll expand on this next week.
Comments
what do i have to wrote in the code where it is the comment “ro do”?
The index method doesn’t have to do much really, apart from load the view for this method.
The view will consist of a form to post your search term. This will post to your result method, which is currently hardcoded with the term ‘Andrew’. You would change this to take the value from the form field.
Clear? If not, I’ll amend the example.
Hi Andy,
Could you please post the content for Zend.php library file( CI ). As the link to Fred Wu site is down.
Thanks for coming up with this search article.
No problem, you can obtain it here. I don’t know if he ever altered it, but this is the version of the code I use on my site.
Hi,
I followed your instruction and got Lucene for Zend to work in Code Igniter on my home server. Unfortunately after i copied it over to the hosted staging server i get these errors whenever i try to execute any Lucene methods:
A PHP Error was encountered
Severity: Notice
Message: Hex number is too big: 0x100000000
Filename: Storage/File.php
Line Number: 268
Do you have any idea what could be wrong?
Thanks
Peter
will it crawl the whole domain going through each link and create the search content?
if that is the case then how can i generate the url link with the search keyword in the search result display?
This example is just a test case that indexes the home page of my site. A more complete example can be found in the next part of this article.
i’ve seen much talk about using lucene as an indexer, but what about using it as the sole data repository? anyone ever try it? how did it preform? how reliable was it? thanks
Hi,
a month ago i sent you comments regarding your article about integration of zend lucene with CI. I have got out of the errors as i reported to you before. but got into some new ones. Now i want to search html docs in my application…every query i m submitting in search is returning no results..when there actually are. i am sending you the code..plz if you can have a look at it and point out my mistake.
Controller
<?php
class Search extends Controller {
function Search()
{
parent::Controller();
$this->load->library(‘zend’);
$this->zend->load(‘Zend/Search/Lucene’);
$this->search_index = APPPATH . ‘search/index’;
}
function create()
{
Zend_Search_Lucene::create($this->search_index);
$doc = Zend_Search_Lucene_Document_Html::loadHTMLFile(‘http://localhost/codeigniter/index.php/universities/home’);
$doc->addField(Zend_Search_Lucene_Field::UnIndexed(‘url’, ‘http://localhost/codeigniter/index.php/universities/home’));
$index->addDocument($doc);
$index->commit();
$index->optimize();
}
function optimize()
{
$this->login();
$index = Zend_Search_Lucene::open($this->search_index);
$index->optimize();
echo ‘
Index optimized.
‘;
}
function result()
{
// Create empty array, in case there are no results.
$data[‘results’] = array();
// If a search_query parameter has been posted, search the index.
if ($this->input->post(‘search_query’))
{
$index = Zend_Search_Lucene::open($this->search_index);
$data[‘results’] = $index->find($this->input->post(‘search_query’));
}
// Load view, and populate with results.
$this->load->view(‘search/search_result’, $data);
}
}
?>
and at search_result view i get every time “No results were returned for query: a”.
can u figure aut my mistake plz.
Please comment on this article. Constructive criticism, ideas, and corrections welcome. In fact, it does not even have to constructive. Feel free to take the p*ss.