This is a FORK from https://github.com/floriansemm/SolrBundle. The original bundle seems to abandoned. I forked the bundle to solve a pretty bad performance issue. Feel free to use this bundle or use the original bundle instead.
This Bundle provides a simple API to index and query a Solr Index.
Installation is a 3 step process:
This bundle is available on Packagist. You can install it using Composer. If you have not yet installed the Solr Bundle, this will be easy. Run the following command:
composer require daanbiesterbos/solr-bundle
Important: If you are currently using the original bundle the update is slightly more tricky.
When you remove the old bundle or when you change the bundle in composer.json, you'll run into issues. Symfony will temporarily not support the fs_solr configuration. Also, composer will automatically remove the bundle from bundles.php. In my opinion this is the most reliable way to migrate from the original bundle.
composer update --no-scripts, this will avoid a failing cache:clear command.Add the bundle to config/bundles.php
return [
FS\SolrBundle\FSSolrBundle::class => ['all' => true],
];
Finally, configure the bundle:
# app/config/config.yml
fs_solr:
endpoints:
core0:
schema: http
host: host
port: 8983
path: /solr/core0
core: corename
timeout: 5
Default values will be used for any option left out.
# app/config/config.yml
fs_solr:
endpoints:
core0:
dsn: http://host:8983/solr
core: core0
timeout: 5
Any values in schema, host, port and path option, will be ignored if you use the dsn option.
To make an entity indexed, you must add some annotations to your entity. Basic configuration requires two annotations:
@Solr\Document(), @Solr\Id(). To index data add @Solr\Field() to your properties.
If you want to index documents without any database, then you have to use the same annotations. Make sure you have set a Id or
set @Solr\Id(generateId=true).
// ....
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", getter="format('Y-m-d\TH:i:s.z\Z')")
*
* @ORM\Column(name="created_at", type="datetime")
*/
private $created_at = null;
}
The bundle handles now updates / inserts / deletions for your configured entity.
@Solr\Document annotationThis annotation denotes that an entity should be indexed as a document. It has several optional properties:
repositoryindexindexHandlerrepository optionIf you specify your own repository, the repository must extend the FS\SolrBundle\Repository\Repository class.
/**
* @Solr\Document(repository="My/Custom/Repository")
*/
class SomeEntity
{
// ...
}
index propertyIt is possible to specify a core the document will be indexed in:
/**
* @Solr\Document(index="core0")
*/
class SomeEntity
{
// ...
}
indexHandler propertyBy default, all documents will be indexed in the core core0. If your entities/documents have different languages, then you can setup
a callback method, which should return the core the entity will be indexed in.
/**
* @Solr\Document(indexHandler="indexHandler")
*/
class SomeEntity
{
public function indexHandler()
{
if ($this->language == 'en') {
return 'core0';
}
}
}
Each core must be set up in config.yml under endpoints. If you leave the index or indexHandler property empty,
then the default core will be used (first one in the endpoints list). To index a document in all cores, use * as index value.
@Solr\Id annotationThis annotation is required to index an entity. The annotation has no properties. You should add this annotation to the field that will be used as the primary identifier for the entity/document.
class Post
{
/**
* @Solr\Id
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
}
generateId optionSet this option to true and a the bundle will generate a Id for you. Use this option if you have no underlying DB which generates incremental Ids for you.
@Solr\Field annotationThis annotation should be added to properties that should be indexed. You should specify the type option for the annotation.
type propertyCurrently, a basic set of types is implemented:
If you have a customized schema.xml than you don't need to setup a field-type.
fieldModifier propertySolr supports partial updates of fields in an existing document. Supported values are:
nestedClass propertySet this property if you want to index collections with nested Objects.
For more information read the more detailed "How to index relation" guide
@Solr\SynchronizationFilter(callback="shouldBeIndexed") annotationIn some cases, an entity should not be indexed. For this, you have the SynchronizationFilter annotation to run a filter-callback.
/**
* // ....
* @Solr\SynchronizationFilter(callback="shouldBeIndexed")
*/
class SomeEntity
{
/**
* @return boolean
*/
public function shouldBeIndexed()
{
// put your logic here
}
}
The callback property specifies an callable function, which should return a boolean value, specifying whether a concrete entity should be indexed.
Querying the index is done via the solr.client service:
$query = $this->get('solr.client')->createQuery('AcmeDemoBundle:Post');
$query->addSearchTerm('title', 'my title');
$query->addSearchTerm('collection_field', array('value1', 'value2'));
$result = $query->getResult();
or
$posts = $this->get('solr.client')->getRepository('AcmeDemoBundle:Post')->findOneBy(array(
'title' => 'my title',
'collection_field' => array('value1', 'value2')
));
The previous examples were only querying the title field. You can also query all fields with a string.
$query = $this->get('solr.client')->createQuery('AcmeDemoBundle:Post');
$query->queryAllFields('my title');
$result = $query->getResult();
If you need more flexiblity in your queries you can define your own query strings:
$query = $this->get('solr.client')->createQuery('AcmeDemoBundle:Post');
$query->setCustomQuery('id:post_* AND (author_s:Name1 OR author_s:Name2)');
$result = $query->getResult();
The query-builder based on https://github.com/minimalcode-org/search Criteria API.
$queryBuilder = $this->get('solr.client')->getQueryBuilder('AcmeDemoBundle:Post');
$result = $queryBuilder
->where('author')
->is('Name1')
->orWhere('author')
->is('Name2')
->getQuery()
->getResult();
To keep your code clean you should move the select-criteria in a repository-class:
class YourRepository extends Repository
{
public function findAuthor($name1, $name2)
{
return $this->getQueryBuilder()
->where('author')
->is($name1)
->orWhere('author')
->is($name2)
->getQuery()
->getResult();
}
}
HydrationMode tells the bundle how to create an entity from a document.
FS\SolrBundle\Doctrine\Hydration\HydrationModes::HYDRATE_INDEX - use only the data from solrFS\SolrBundle\Doctrine\Hydration\HydrationModes::HYDRATE_DOCTRINE - merge the data from solr with the entire doctrine-entityWith 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);
}
Your should define your own repository-class to make your custom queries reuseable. How to configure a repository for a document have a look at the annotation section
namespace AppBundle\Search;
use FS\SolrBundle\Repository\Repository;
class ProviderRepository extends Repository
{
public function findPost($what)
{
$query = $this->solr->createQuery('AcmeDemoBundle:Post');
// some query-magic here
return $query->getResult();
}
}
In your repository you have full access to the querybuilder.
Here's all the commands provided by this bundle:
solr:index:clear - delete all documents in the indexsolr:index:populate - synchronize the db with the indexsolr:schema:show - shows your configured documentsThe solr:index:populate command works well for sets up to 300k entities, everthing large makes the command very slow. You can find here some solution how to sync your DB with Solr.
To extend Solarium with your own plugins, create a tagged service:
<tag name="solarium.client.plugin" plugin-name="yourPluginName"/>
To hook into the Solarium events create a common Symfony event-listener:
<tag name="kernel.event_listener" event="solarium.core.preExecuteRequest" method="preExecuteRequest" />
$helper = $this->get('solr.client')->getDocumentHelper();
$id = $helper->getLastInsertDocumentId();
How can I help you explore Laravel packages today?