Doctrine Search
注意:此项目目前是原型。有关实际实施示例,请参阅 demo 文件夹。
支持的搜索引擎
- ElasticSearch (实用)
- Solr (部分实施)
特性
- SearchManager
- 可以单独使用或以混合配置使用
- 可配置的搜索管理器支持聚合实体管理器
- 支持通过搜索引擎适配器(如Elastica)直接进行API调用
- 根据需要将返回的ID通过批处理操作转换为水合对象
- 支持可自定义实体处理的事件管理器侦听器
- 支持通过JMS Serializer通过事件侦听器进行索引或简单的实体回调。
- 使用ObjectManager::getClassMetadata()作为基础结构创建索引和数据类型的注释
用法
配置
搜索管理器连接可以按照以下示例进行配置:
$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') ) ); $eventManager = new Doctrine\Search\EventManager(); $eventManager->addListener($listener); $searchManager = new Doctrine\Search\SearchManager( $config, new Doctrine\Search\ElasticSearch\Client( new Elastica\Client(array( array('host' => 'localhost', 'port' => '9200') ) ), $eventManager );
Mappings(映射)
索引和类型生成的基本实体映射可以注释,如以下示例所示。映射 可以被渲染成适合使用构建脚本自动生成索引和类型的格式 (需要高级设置)。
<?php namespace Entities; use Doctrine\Search\Mapping\Annotations as MAP; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @MAP\ElasticSearchable(index="indexname", type="post", source=true) */ class Post { /** * @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(索引)
可以通过以下方式序列化文档以进行索引编制。如果需要,事件监听器可以 与本例中所示的ORM一起使用。如果不需要事件侦听器,则实体可以被持久化 或者使用搜索管理器直接删除。
<?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
这个方法只需要在实体上使用一个 toArray()方法,不过这个方法可以根据需要进行配置。 只要您的事件侦听器可以识别,本示例中提供的接口可以是您所需的任何接口 需要坚持到搜索引擎的实体(参见上面的例子)。
... use Entities\Behaviour\SearchableEntityInterface class Post implements SearchableEntityInterface { ... public function toArray() { return array( 'id' => $this->id, 'title' => $this->title, 'content' => $this->content ... ); } }
JMS Serializer(JMS序列化)
您也可以使用 JMS Serializer 的高级序列化功能自动处理 根据例如本示例中显示的注释序列化您。
... 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
尚未公布。
查询
查询可以通过搜索管理器执行,如下所示。使用结果缓存指的是使用 缓存水合查询。就像这样,搜索引擎特定的适配器接口就会被神奇地暴露出来 例如, Elastica\Query::addSort 方法与 Doctrine\Search\Query 方法合并。因此任何复杂性 支持由搜索引擎客户端库支持的查询。
$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();
通过使用以下技术可以完成简单存储库ID查询和 Term 搜索。反序列化完成 独立于 Doctrine\ORM ,但是相同的模型根据注册的 SerializerInterface 进行水合(hydrated)。
$entity = $searchManager->getRepository('Entities\Post')->find($id); $entity = $searchManager->getRepository('Entities\Post')->findOneBy(array($key => $term));