我写了一个 ZF2 弹性搜索模块,但它是闭源的。它使模块能够将可搜索的数据放入 ES。我不能发布代码,但我可以解释它是如何工作的。
中央模块是Search
。搜索包含两个主要界面:Search\Repository\ItemRepositoryInterface
和Search\Service\ItemServiceInterface
。存储库用于搜索项目,用于存储/删除项目的服务。
interface ItemRepositoryInterface
{
public function search($query, $limit = 10);
}
interface ItemServiceInterface
{
public function insert(SearchableInterface $object);
public function remove(SearchableInterface $object);
}
SearchableInterface
是我的模型/实体可以用来“使其”可搜索的界面。它让 ES 设置 ES id 并获取类型。通常,每个实体都有自己的类型(因此我可以搜索所有图像和项目,或仅查询图像类型)。
我已经为博客/事件系统实现了这个。将博客文章持久化到数据库中的服务类触发事件,而 ElasticSearch 是侦听器之一:
public function onBootstrap(MvcEvent $e)
{
$app = $e->getApplication();
$sm = $app->getServiceManager();
$em = $app->getSharedManager();
$em->attach('Blog\Service\ArticleService', 'create', function($e) use ($sm) {
$searchService = $sm->get('Search\Service\ItemService');
$article = $e->getArticle();
$searchService->insert($article);
});
}
因为Article
implements SearchableInterface
,所以效果很好。现在我的博客不必处理搜索,搜索也不必处理博客。但是,您想知道,文章是如何转换为搜索文档的?
我有一个类似于 ZF2 水合器的水合器机制。它不会将任何对象转换为数组(反之亦然)。它将SearchableInterface
对象转换为 Elastic Search Document
(用于存储对象),并将 Elastic Search Result
(在搜索查询后返回)SearchableInterface
再次转换为对象。
interface HydratorInterface
{
public function extract(SearchableInterface $object);
public function hydrate(Result $object);
}
每种类型都有自己注册的保湿剂。所有这些不同的水合器都被收集到一个HydratorManager
基本上是一个Zend\ServiceManager\AbstractPluginManager
. 这个插件管理器被注入到存储库和服务中。
因此,在服务内部,会发生以下情况:
- 已
$object->getType()
检查
- 对于它的类型,获取对应的 hydrator
- 水合
extract()
器被称为$object
将$document
- 底层 ES 客户端用于持久化文档(是添加还是更新,取决于
$object->getElasticSearchId()
对于存储库,给定一个查询type:image name:Mountain
,会发生以下情况:
search()
使用给定查询调用存储库
- 该字符串用于 ES 查询对象并被执行
- 结果被迭代
- 对于每个结果,都会检查类型
- 对于它的类型,获取对应的 hydrator
- 水合
hydrate()
器被称为$result
将$object
- 返回对象的集合