floriansemm/solr-bundle

Symfony2 Solr integration bundle

Installs: 12 605

Dependents: 1

Stars: 82

Watchers: 14

Forks: 52

Open Issues: 12

Type: symfony-bundle

1.4 2016-04-27 04:57 UTC

README

Build Status Latest Stable Version Total Downloads

Introduction

This Bundle provides a simple API to index and query a Solr Index.

Installation

Installation is a quick (I promise!) 3 step process:

  1. Download SolrBundle
  2. Enable the Bundle
  3. Configure the SolrBundle

Step 1: Download SolrBundle

This bundle is available on Packagist. You can install it using Composer:

$ composer require floriansemm/solr-bundle

Step 2: Enable the bundle

Finally, enable the bundle in the kernel

<?php
// app/AppKernel.php

public function registerBundles()
{
    $bundles = array(
        // ...
        new FS\SolrBundle\FSSolrBundle(),
    );
}

Step 3: Configure the SolrBundle

# app/config/config.yml
fs_solr:
    endpoints:
        core0:
            host: host
            port: 8983
            path: /solr/core0
            core: corename
            timeout: 5

Step 4: Configure your entities

To put an entity to the index, you must add some annotations to your entity. Basic configuration requires two annoations: @Solr\Document(), @Solr\Id(). This two annotations makes a entity indexable. To index data add @Solr\Field() to your properties.

// ....
use FS\SolrBundle\Doctrine\Annotation as Solr;

/**
* @Solr\Document()
* @ORM\Table()
*/
class Post
{
    /**
     * @Solr\Id
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @Solr\Field(type="string")
     *
     * @ORM\Column(name="title", type="string", length=255)
     */
    private $title = '';

    /**
     * @Solr\Field(type="string")
     *
     * @ORM\Column(name="text", type="text")
     */
    private $text = '';

   /**
    * @Solr\Field(type="date")
    *
    * @ORM\Column(name="created_at", type="datetime")
    */
    private $created_at = null;
}

Annotation reference

@Solr\Document annotation

Entities must have this annotation to mark them as document. It has two optional properties: repository, index, indexHandler

Setup custom repository class with repository option

If you specify your own repository you must extend the FS\SolrBundle\Repository\Repository class.

/**
 * @Solr\Document(repository="My/Custom/Repository")
 */
class SomeEntity
{
    // ...
}

index property

It is possible to specify a core dedicated to a document

/**
 * @Solr\Document(index="core0")
 */
class SomeEntity
{
    // ...
}

indexHandler property

All documents will be indexed in the core core0. If your entities/document have different languages then you can setup a callback method, which returns the preferred core for the entity.

/**
 * @Solr\Document(indexHandler="indexHandler")
 */
class SomeEntity
{
    public function indexHandler()
    {
        if ($this->language == 'en') {
            return 'core0';
        }
    }
}

Each core must setup up in the config.yml under endpoints. If you leave the index or indexHandler property empty, then a default core will be used (first in the endpoints list). To index a document in all cores use * as index value:

@Solr\Id annotation

This is required for entites to index them. The annotation has no futher properties.

class Post
{
    /**
     * @Solr\Id
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */

    private $id;
}

@Solr\Field annotation

Add this annotation with a type to a property an the value will be indexed.

Supported simple field types

Currently is a basic set of types implemented.

  • string(s)
  • text(s)
  • date(s)
  • integer(s)
  • float(s)
  • double(s)
  • long(s)
  • boolean(s)

Object relations

Indexing of relations works in simplified way. Related entities will not indexed as a new document only a searchable value. Related entity do not need a @Solr\Document annotation.

ManyToOne relation
/**
 * @var Category
 *
 * @Solr\Field(type="string", getter="getTitle")
 *
 * @ORM\ManyToOne(targetEntity="Acme\DemoBundle\Entity\Category", inversedBy="posts", cascade={"persist"})
 * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
 */
private $category;

Related entity:

class Category
{
    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }
}
OneToMany relation

To index a set of objects it is important to use the fieldtype strings.

/**
 * @var Tag[]
 *
 * @Solr\Field(type="strings", getter="getName")
 *
 * @ORM\OneToMany(targetEntity="Acme\DemoBundle\Entity\Tag", mappedBy="post", cascade={"persist"})
 */
private $tags;

Related entity:

class Tag
{
    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }
}

For more information read the more detailed "How to index relation" guide

@Solr\SynchronizationFilter(callback="shouldBeIndex") annotation

In some cases a entity should not be index. For this you have the SynchronizationFilter annotation to run a filter-callback.

/**
 * // ....
 * @Solr\SynchronizationFilter(callback="shouldBeIndex")
 */
class SomeEntity
{
    /**
     * @return boolean
    */
    public function shouldBeIndex()
    {
        // put your logic here
    }
}

The callback property specifies an callable function, which decides whether the should index or not.

Queries

Query a field of a document

To query the index you have to call some services.

$query = $this->get('solr.client')->createQuery('AcmeDemoBundle:Post');
$query->addSearchTerm('title', 'my title');

$result = $query->getResult();

or

$posts = $this->get('solr.client')->getRepository('AcmeDemoBundle:Post')->findOneBy(array(
    'title' => 'my title'
));

Query all fields of a document

The pervious examples have queried only the field 'title'. You can also query all fields with a string.

$query = $this->get('solr.client')->createQuery('AcmeDemoBundle:Post');
$query->queryAllFields('my title');

$result = $query->getResult();

Define Result-Mapping

To narrow the mapping, you can use the addField() method.

$query = $this->get('solr.client')->createQuery('AcmeDemoBundle:Post');
$query->addSearchTerm('title', 'my title');
$query->addField('id');
$query->addField('text');

$result = $query->getResult();

In this case only the fields id and text will be mapped (addField()), so title and created_at will be empty. If nothing was found $result is empty.

The result contains by default 10 rows. You can increase this value:

$query->setRows(1000000);

Configure HydrationModes

HydrationMode tells the Bundle how to create an entity from a document.

  1. FS\SolrBundle\Doctrine\Hydration\HydrationModes::HYDRATE_INDEX - use only the data from solr
  2. FS\SolrBundle\Doctrine\Hydration\HydrationModes::HYDRATE_DOCTRINE - merge the data from solr with the entire doctrine-entity

With a custom query:

$query = $this->get('solr.client')->createQuery('AcmeDemoBundle:Post');
$query->setHydrationMode($mode)

With a custom document-repository you have to set the property $hydrationMode itself:

public function find($id)
{
    $this->hydrationMode = HydrationModes::HYDRATE_INDEX;

    return parent::find($id);
}

Commands

There are two commands with this bundle:

  • solr:index:clear - delete all documents in the index
  • solr:index:populate - synchronize the db with the index
  • solr:schema:show - shows your configured documents