I use ZF2 Search Lucene for searching the products on the site. I need to search the products using user's input text, and filter the result by several parameters such as Category and Type by id. But the catch is that user's input are searched in all fields, and I need to search only in Name and Description fields.
Here's the code for adding products to index:
$index = Lucene::create('./data/index');
$products = $this->getEntityManager()->getRepository('Application\Entity\Product')->findAll();
foreach ($products as $product) {
echo "Adding ".$product->getName(). " to index
";
$doc = new LuceneDocument();
$doc->addField(LuceneDocument\Field::keyword('type', 'product'));
$doc->addField(LuceneDocument\Field::keyword('product_id', (string)$product->getId()));
$doc->addField(LuceneDocument\Field::keyword('category_id', (string)$product->getCategory()->getId()));
$fieldName = LuceneDocument\Field::text('product_name', $product->getName());
$fieldName->boost = 2.0; // Field weight
$doc->addField($fieldName);
$fieldDescription = LuceneDocument\Field::unStored('product_description', $product->getDescription());
$fieldDescription->boost = 1.0; // Field weight
$doc->addField($fieldDescription);
$index->addDocument($doc);
}
$index->commit();
Code for searching:
$userQueryString = 'search input query string';
$userQuery = LuceneSearch\QueryParser::parse($userQueryString);
// how to limit userQuery to search only in specific fields?
$typeTerm = new LuceneIndex\Term('product', 'type');
$typeQuery = new LuceneSearch\Query\Term($typeTerm);
$categoryTerm = new LuceneIndex\Term(5, 'category_id');
$categoryQuery = new LuceneSearch\Query\Term($categoryTerm);
$query = new LuceneSearch\Query\Boolean();
$query->addSubquery($typeQuery, true /* required */);
$query->addSubquery($categoryQuery, true /* required */);
$query->addSubquery($userQuery, true /* required */);
$index = Lucene::open('./data/index');
$hits = $index->find($query);
foreach ($hits as $hit) {
echo "Type: ".$hit->type."
";
echo "Id: ".$hit->product_id."
";
echo "Name: ".$hit->product_name."
";
echo "Category: ".$hit->category_id."
";
echo "
";
}
The documentation stands that
The first and most significant difference from Java Lucene is that terms are searched through all fields by default.
If you want to use LuceneSearch\QueryParser::parse()
method, you can prepare the $userQueryString
like this:
$userQueryString = 'name:search input query string description:search input query string';
Also you can use Zend\Search\Lucene\Search\Query\MultiTerm::addTerm()
method like this:
...
$userQuery = new Zend\Search\Lucene\Search\Query\MultiTerm();
$userQuery->addTerm(new Zend\Search\Lucene\Index\Term($userQueryString, 'name'));
$userQuery->addTerm(new Zend\Search\Lucene\Index\Term($userQueryString, 'description'));
...
$query->addSubquery($userQuery, true /* required */);