Filtering sfLucene Results

Often I need to add the ability to filter sfLucenes search results by certain criteria (price, category, etc). While im sure that it can probably be done using the plugins configuration files, its quite simple to just write your own simple interface.

$lucene = sfLucene::getInstance('ProductIndex', 'en');
$query = new sfLuceneCriteria($lucene);
$query->addSane($this->getRequestParameter('q'));
$results = $lucene->friendlyFind($query);
 
foreach ($results as $result)
{
    $matched_products[] = $result->getId();
}

The $matched_products array now contains all the product ID’s that were found. So now I ran a query applying the nessecary filters and use the IN() operator to limit it to the products found by Lucene. In the example I havent applied any of my filters, I am only checking that the product is active.

$c = new Criteria();
$c->add(ProductsPeer::ID, $matched_products, Criteria::IN);
$c->add(ProductsPeer::ACTIVE, 1);
$this->products = ProductsPeer::doSelect($c);

The only problem I ran into is that results of this query won’t be in the same order as Lucenes results, by default it will order it by the ID’s. After some investigation I discovered the mysql CASE statement.

if (count($matched_products) > 0)
{
 
  $order_by = ' case ('.ProductsPeer::ID.')';
  $count = 1;
  foreach ($matched_products AS $id)
  {
        $order_by .= ' when '.$id.' then '.$count.' ';
        $count++;
  }
  $order_by .= ' end ';
 
  $c->addAscendingOrderByColumn( $order_by , Criteria::CUSTOM);
 
}

Apply the above code to your query and the results will be returned in the same order as $matched_products.

Tags: ,

No comments yet.

Leave a Reply