Skip to content
Browse files

Update README.markdown

  • Loading branch information...
1 parent bebb702 commit 629b826f39c055a9ac3917909ef67cb037d9902a @MrHash MrHash committed Sep 11, 2013
Showing with 183 additions and 35 deletions.
  1. +183 −35 README.markdown
View
218 README.markdown
@@ -1,56 +1,204 @@
# Doctrine Search #
-Note: This project is a prototype at the moment.
+Note: This project is a prototype at the moment.
__Supported search engines__
-* [ElasticSearch](http://www.elasticsearch.org/)
-* [Solr](http://lucene.apache.org/solr/)
-* [ZendLucene](http://framework.zend.com/manual/en/zend.search.lucene.html)
+* [ElasticSearch](http://www.elasticsearch.org/) (functional)
+* [Solr](http://lucene.apache.org/solr/) (partial implementation)
+* [ZendLucene](http://framework.zend.com/manual/en/zend.search.lucene.html) (partial implementation)
-## Todo convert this into items ##
-* SearchService
- * aggregates a ObjectManager instance: $searchManager = new SearchManager($objectManager);
- * supports direct API calls (Solr, Lucene, ... Adapter useable)
- * transforms returned ID"s via batch operation into objects
-* EventListener for indexing, new SearchIndexListener($backendAdapter);
-* uses ObjectManager::getClassMetadata() as the base structure
-* adds new Annotationen for more complexe configuration needs
+__Features__
+* SearchManager
+ * Can be used stand-alone or in a hybrid configuration
+ * Configurable search manager supports aggregate entity manager
+ * supports direct API calls through search engine adapters such as Elastica
+ * transforms returned ID's via batch operation into hydrated objects as required
+* Support for indexing through event listeners via JMS Serializer or simple entity callback.
+* Annotations for index and data type creation using ObjectManager::getClassMetadata() as the base structure
-## Usage ##
+#Usage#
+## Configuration ##
+The search manager connection can be configured as shown in the following example:
+```php
+$config = new Doctrine\Search\Configuration();
+$config->setMetadataCacheImpl(new Doctrine\Common\Cache\ArrayCache());
+$config->setEntitySerializer(
+ new Doctrine\Search\Serializer\JMSSerializer(
+ JMS\Serializer\SerializationContext::create()->setGroups('search')
+ )
+);
+
+$searchManager = new Doctrine\Search\SearchManager(
+ $config,
+ new Doctrine\Search\ElasticSearch\Client(
+ new Elastica\Client(array(
+ array('host' => 'localhost', 'port' => '9200')
+ )
+ )
+);
+```
+
+## Mappings ##
+Basic entity mappings for index and type generation can be annotated as shown in the following example. Mappings
+can be rendered into a format suitable for automatically generating indexes and types using a build script
+(advanced setup required).
```php
<?php
namespace Entities;
-use Doctrine\Search\Mapping\Annotation as Search;
+use Doctrine\Search\Mapping\Annotations as MAP;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
- * @Search\Searchable
+ * @MAP\ElasticSearchable(index="indexname", type="post", source=true)
*/
class Post
{
- /**
- * @var integer
- * @ORM\Id @ORM\GeneratedValue(strategy="AUTO")
- */
- public $id;
-
- /**
- * @var string
- * @ORM\Column(type="string")
- * @Search\Field
- */
- public $title;
-
- /**
- * @var string
- * @ORM\Column(type="text")
- * @Search\Field
- * @Search\SolrField
- */
- public $content;
+ /**
+ * @ORM\Id
+ * @ORM\GeneratedValue(strategy="AUTO")
+ * @MAP\ElasticField(type="integer", includeInAll=false)
+ */
+ private $id;
+
+ /**
+ * @ORM\Column(type="string")
+ * @MAP\ElasticField(type="string", includeInAll=true, boost=5.0)
+ */
+ private $title;
+
+ /**
+ * @ORM\Column(type="text")
+ * @MAP\ElasticField(type="string", includeInAll=true)
+ */
+ private $content;
+
+ /**
+ * @MAP\ElasticField(name="tags", type="string", includeInAll=false, index="not_analyzed")
+ */
+ public function getTags() {
+ return $this->tags->slice(0,3);
+ }
}
+```
+
+## Indexing ##
+Documents can be serialized for indexing currently in the following ways. If required an event listener can
+be used with your ORM as shown in this example. If an event listener is not needed, entities can be persisted
+or removed directly using the search manager.
+```php
+<?php
+namespace Entities\Listener;
+
+use Doctrine\ORM\Event\LifecycleEventArgs;
+use Entities\Behaviour\SearchableEntityInterface;
+
+class SearchableListener implements
+{
+ protected function getSearchManager() {
+ return $this->getDatabaseConnection('elasticsearch');
+ }
+
+ public function postPersist(LifecycleEventArgs $oArgs) {
+ $oEntity = $oArgs->getEntity();
+ if($oEntity instanceof SearchableEntityInterface) {
+ $this->getSearchManager()->persist($oEntity);
+ }
+ }
+
+ public function postRemove(LifecycleEventArgs $oArgs) {
+ $oEntity = $oArgs->getEntity();
+ if($oEntity instanceof SearchableEntityInterface) {
+ $this->getSearchManager()->remove($oEntity);
+ }
+ }
+}
+```
+
+### CallbackSerializer ###
+This approach simply expects a `toArray()` method on the entity, although this method be configured as required.
+The interface suggested in this example can be any interface you desire, as long as your event listener can identify
+entities that need to be persisted to the search engine (see above example).
+```php
+...
+use Entities\Behaviour\SearchableEntityInterface
+
+class Post implements SearchableEntityInterface
+{
+ ...
+ public function toArray() {
+ return array(
+ 'id' => $this->id,
+ 'title' => $this->title,
+ 'content' => $this->content
+ ...
+ );
+ }
+}
+```
+
+### JMS Serializer ###
+You can alternatively use the advanced serialization power of the `JMS Serializer` to automatically handle
+serialization for you based on annotations such as those shown in this example.
+```php
+...
+use JMS\Serializer\Annotation as JMS;
+use Entities\Behaviour\SearchableEntityInterface
+
+/**
+ * @ORM\Entity
+ * @MAP\ElasticSearchable(index="indexname", type="post", source=true)
+ * @JMS\ExclusionPolicy("all")
+ */
+class Post implements SearchableEntityInterface
+{
+ ...
+ /**
+ * @ORM\Column(type="string")
+ * @MAP\ElasticField(type="string", includeInAll=true, boost=5.0)
+ * @JMS\Expose
+ * @JMS\Groups({"public", "search"})
+ */
+ private $title;
+
+ /**
+ * @ORM\Column(type="text")
+ * @MAP\ElasticField(type="string", includeInAll=true)
+ * @JMS\Expose
+ * @JMS\Groups({"public", "search"})
+ */
+ private $content;
+ ...
+}
+```
+
+### AnnotationSerializer ###
+Not yet available.
+
+
+## Queries ##
+Queries can be executed through the search manager as shown below. Use of the result cache refers to using the
+cache for the hydration query. Search engine specific adapter interfaces are exposed magically so as in this
+example, `Elastica\Query::addSort` method is amalgamated with `Doctrine\Search\Query` methods. Thus any complexity
+of query supported by the search engine client library is supported.
+```php
+$hydrationQuery = $entityManager->createQueryBuilder()
+ ->select(array('p', 'field(p.id, :ids) as HIDDEN field'))
+ ->from('Entities\Post', 'p')
+ ->where('p.id IN (:ids)')
+ ->orderBy('field')
+ ->getQuery();
+
+$query = $searchManager->createQuery()
+ ->from('Entities\Post')
+ ->searchWith(new Elastica\Query())
+ ->hydrateWith($hydrationQuery)
+ ->addSort('_score')
+ ->setFrom(0)
+ ->setLimit(10)
+ ->getResult();
+```

0 comments on commit 629b826

Please sign in to comment.
Something went wrong with that request. Please try again.