简体   繁体   中英

How to integrate Elasticsearch in Zend Framework 2 using Doctrine 2

I followed this tutorial for integrating doctrine with Zend Framework 2. Now, all is working fine, but I would like to integrate Elasticsearch to this project.

I found a lot of documentation about Elasticsearch, I downloaded the Elastica plugin for PHP, but I don't know where to get started.

I searched tutorials to integrate Elasticsearch with Doctrine, but they're all about Symfony. Could someone please explain me (in a simple way) how to use ElasticSearch in Zend Framework 2, using Doctrine 2 as ORM to index and search through my objects?

There are no direct relation exists between Doctrine 2 and Elasticsearch . While primary concern of Doctrine ORM is persisting, updating and reading data on relational databases, elasticsearch mainly focuses on indexing and searching that data. Instead of thinking about "integrating elasticsearch with doctrine" , think about "how can i use both doctrine and elasticsearch in same application" .

Whenever you create or update a record in database, you would probably want to do more operations like indexing that data on Elasticsearch or Solr , caching or invalidating already cached version of same data on Memcached or Redis etc.. To do that properly (or zf2 way), you should carefully design a service layer which orchestrates both persistency operations and related post-processes like indexing on elasticsearch, caching, cache invalidating, logging etc..

Accomplishing some of these operations by firing some events via EventManager would be an appropriate decision.

Note: Don't utilize EventManager heavily for simple & straightforward tasks such as writing a log line. Events are not free, especially in ZF2. ( Quite improved in ZF3, but still not free ).


For question, here is the way to go with Zend Framework 2 while utilizing a 3rd party library which is ruflin/elastica :

A. Open your terminal and type

$ cd /path/to/your/project
$ php composer.phar selfupdate
$ php composer.phar require ruflin/elastica:dev-master

B. Create a factory for elastica client Application\\Service\\ElasticaClientFactory.php

<?php
namespace Application\Service;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class ElasticaClientFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $sl)
    {
        $config = $sl->get('Config');
        $clientOptions = isset($config['elastica']) ? $config['elastica'] : array();
        $client = new \Elastica\Client($clientOptions);

        return $client;
    }
}

C. Add elastica configuration and register new factory class to service locator in your module.config.php :

'elastica' => array(
    'servers' => array(
        array('host' => '127.0.0.1','port' => 9200),
        // You can add more servers when necessary
        // array('host' => '127.0.0.1','port' => 9200)
        ),
    ),

service_manager' => array(
    'factories' => array(
        'elastica-client' => 'Application\Service\ElasticaClientFactory'
    ),
)

At this point, in any controller (bad) or service (good) you can grab the elastica client instance like this:

$elastica = $this->getServiceLocator()->get('elastica-client');

Bonus: Using Service Initializers and Traits

If your PHP version is ≥ 5.4 you can use traits while automatically injecting the Elastica Client into your services with the help of service initializers .

D. Create a new interface named Application\\Service\\ElasticaAwareInterface.php

<?php
namespace Application\Service;

interface ElasticaAwareInterface
{
    public function getElasticaClient();
    public function setElasticaClient(\Elastica\Client $client);
}

E. Create a new trait named Application\\Traits\\ElasticaAwareTrait.php (Notice the path. Create the Traits folders if doesn't exists)

<?php
namespace Application\Traits;

trait ElasticaAwareTrait
{
    protected $client = null;

    public function getElasticaClient()
    {
        return $this->client;
    }

    public function setElasticaClient(\Elastica\Client $client)
    {
        $this->client = $client;
        return $this;
    }
}

F. Create a new initializer named Application\\Initializers\\ElasticaInitializer.php (Notice the path, again)

<?php
namespace Application\Initializers;

use Zend\ServiceManager\InitializerInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Application\Service\ElasticaAwareInterface;

class ElasticaInitializer implements InitializerInterface
{
    /**
     * Initializer for the elastica-aware domain services.
     * Properly creates a new elastica client and injects it into related service.
     */
    public function initialize($service, ServiceLocatorInterface $serviceManager)
    {
        /**
         * Beware: This if statement will be run for every service instance
         * we grab from $serviceManager because the nature of initializers.
         * This worth think about on it. With ZF3 this went further. 
         * We may load our services lazily using delegator factories.
         */ 
        if ($service instanceof ElasticaAwareInterface) {
            $service->setElasticaClient( $serviceManager->get('elastica-client') );
        }
    }
}

So far so good. Now, we can put together all parts. Say, we have a service named UserService which uses a Doctrine entity manger (or UserRepository better), also needs to use Elastica .

G. Register our service to service manager:

service_manager' => array(
    'factories' => array(
        'elastica-client' => 'Application\Service\ElasticaClientFactory'
    ),
    'invokables' => array(
        'user-service' => 'Application\Service\UserService'
    )
)

Finally, the UserService signature:

<?php
namespace Application\Service;

use Application\Service\ElasticaAwareInterface;

class UserService implements ElasticaAwareInterface
{
    // Here is our trait
    use \Application\Traits\ElasticaAwareTrait;

    public function fooMethod()
    {
        // Do some things with doctrine EM here..

        // And grab the elastica client easily anywhere in UserService
        $client = $this->getElasticaClient();
    }
}

There are some (still under heavy development) modules out there that combine Doctrine2 and ElasticSearch. For example check out this module called OcraElasticSearch from the Doctrine2+ZF2 Master @Ocramius himself :)

Otherwise it seems that Symfony2 is a step ahead when it comes to integrating Doctrine and ElasticSearch.

I bet within one or two months you should be able to find more alternatives on GitHub.

Since we need similar functionality soon I might discover more later. If I do I will update my post.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM