Skip to content

Instantly share code, notes, and snippets.

@remialvado
Last active December 10, 2015 01:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save remialvado/4363553 to your computer and use it in GitHub Desktop.
Save remialvado/4363553 to your computer and use it in GitHub Desktop.
How to hack RiakBundle to use custom mount point for search feature on one single bucket

Use case


Let's say you have a Riak bucket containing points of interests (bars, restaurants, movie theatres, ...) and you have already hacked Riak to allow your application to perform localized searches using HTTP (Solr-like) interface. Example : http://localhost:8098/riak/localsolr/points_of_interests/search?q="title:sushi"&lat=48.859871&lon=2.3633826

Solution


We need to use a custom Bucket class for the "points_of_interest" bucket. This class will add a "localSearch" method that will call a RiakSearchServiceClient with a modified mount point.

Detailled solution


We just add a new "points_of_interests" bucket with a custom Class

This class extends the base Bucket class and add a new localSearch method that depends on a custom RiakSearchServiceClient service. This service will be defined later on services.xml

This service listen to "riak.add.bucket" events and injects the riakLocalSearchServiceClient instance into each Bucket that are instance of AcmeBucket

LocalQuery is a superclass of Query and is used to perform local searches on bucket that supports them.

This configuration file describes :

  • the route to query Riak Local Search mount point
  • the localSearch service using the riak based search service
  • the bucket builder and defines which event is listened and what method is called when this event is fired

A really basic example of how to use this hack.

<?php
namespace Acme\DemoBundle\Model;
use \Kbrw\RiakBundle\Model\Bucket\Bucket;
class AcmeBucket extends Bucket
{
/**
* @param string | \Acme\DemoBundle\Model\LocalQuery $query
* @return \Kbrw\RiakBundle\Model\Search\Response
*/
public function localSearch($query)
{
return $this->riakLocalSearchServiceClient->search($this->cluster, $this, $query);
}
/**
* @var \Kbrw\RiakBundle\Service\WebserviceClient\Riak\RiakSearchServiceClient
*/
protected $riakLocalSearchServiceClient;
public function getRiakLocalSearchServiceClient()
{
return $this->riakLocalSearchServiceClient;
}
public function setRiakLocalSearchServiceClient($riakLocalSearchServiceClient)
{
$this->riakLocalSearchServiceClient = $riakLocalSearchServiceClient;
}
}
<?php
namespace Acme\DemoBundle\DependencyInjection;
class BucketBuilder
{
/**
* @var \Kbrw\RiakBundle\Service\WebserviceClient\Riak\RiakSearchServiceClient
*/
protected $riakLocalSearchServiceClient;
public function getRiakLocalSearchServiceClient()
{
return $this->riakLocalSearchServiceClient;
}
public function setRiakLocalSearchServiceClient($riakLocalSearchServiceClient)
{
$this->riakLocalSearchServiceClient = $riakLocalSearchServiceClient;
}
/**
*
* @param \Symfony\Component\EventDispatcher\GenericEvent $event
*/
public function onRiakAddBucket($event)
{
$bucket = $event->getArgument("bucket");
if ($bucket instanceof \Acme\DemoBundle\Model\AcmeBucket) {
$bucket->setRiakLocalSearchServiceClient($this->riakLocalSearchServiceClient);
}
}
}
riak:
clusters:
backend:
domain: "127.0.0.1"
port: "8098"
client_id: "frontend"
buckets:
users:
fqcn: 'Acme\DemoBundle\Model\User'
format: json
cities:
fqcn: 'Acme\DemoBundle\Model\City'
format: xml
points_of_interests:
fqcn: 'Acme\DemoBundle\Model\PointOfInterest'
format: json
class: 'Acme\DemoBundle\Model\AcmeBucket'
<?php
namespace Acme\DemoBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Acme\DemoBundle\Form\ContactType;
// these import the "@Route" and "@Template" annotations
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class DemoController extends Controller
{
/**
* @Route("/{term}/{lat}/{lon}", name="_demo_local_search")
* @Template()
*/
public function localSearchAction($term, $lat, $lon)
{
$query = new \Acme\DemoBundle\Model\LocalQuery("title:" . $term, $lat, $lon);
$cluster = $this->get("riak.cluster.backend");
$cluster->getBucket("points_of_interests")->saSearch($query);
}
}
<?php
namespace Acme\DemoBundle\Model;
use \Kbrw\RiakBundle\Model\Search\Query;
class LocalQuery extends Query
{
protected $lat;
protected $lon;
public function getConfig()
{
$config = parent::getConfig();
if(!empty($this->lat)) $config["lat"] = $this->lat;
if(!empty($this->lon)) $config["lon"] = $this->lon;
return $config;
}
function __construct($query = null, $lat = null, $lon = null, $fieldsList = array(), $start = 0, $rows = 10, $defaultField = null, $operation = null, $sort = null, $wt = "xml", $filter = null)
{
parent::__construct($query, $fieldsList, $start, $rows, $defaultField, $operation, $sort, $wt, $filter);
$this->setLat($lat);
$this->setLon($lon);
}
public function getLat()
{
return $this->lat;
}
public function setLat($lat)
{
$this->lat = $lat;
}
public function getLon()
{
return $this->lon;
}
public function setLon($lon)
{
$this->lon = $lon;
}
}
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="acme.riak.search.route">{protocol}://{domain}:{port}/localsolr/{bucket}/select{?q,start,rows,df,q.op,sort,wt,filter,fl,lat,lon}</parameter>
</parameters>
<services>
<service id="acme.riak.sasearch" class="%kbrw.riak.search.class%">
<call method="setRoute">
<argument>%acme.riak.search.route%</argument>
</call>
<call method="setLogger">
<argument type="service" id="logger" />
</call>
<call method="setSerializer">
<argument type="service" id="jms_serializer" />
</call>
</service>
<service id="acme.bucket.builder" class="Acme\DemoBundle\DependencyInjection\BucketBuilder">
<tag name="kernel.event_listener" event="riak.bucket.add" method="onRiakAddBucket" />
<call method="setRiakLocalSearchServiceClient">
<argument type="service" id="acme.riak.sasearch" />
</call>
</service>
</services>
</container>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment