如何在SonataAdminBundle中集成Elasticsearch替代Doctrine实现搜索
在SonataAdminBundle中用Elasticsearch替代Doctrine实现搜索
嘿,我来帮你搞定SonataAdminBundle里切换到Elasticsearch搜索的事儿!你已经完成了ES部署和fos_elastica的基础配置,接下来咱们一步步把搜索逻辑从Doctrine换成ES:
1. 补全fos_elastica的完整配置
首先把你没写完的配置补全,确保实体和ES索引/类型正确映射:
# config/packages/fos_elastica.yaml fos_elastica: clients: default: { host: localhost, port: 9200 } indexes: symfony: types: product: persistence: driver: orm model: App\Entity\Product # 替换成你的实体完整路径 provider: ~ # 启用数据提供者,用于同步实体到ES finder: ~ # 启用查找器,用于从ES查询数据 properties: # 映射你实体里需要搜索的字段,比如name、description、price name: ~ description: ~ price: ~
2. 创建自定义Elastica Repository(可选但推荐)
为了更灵活地控制ES查询,咱们可以创建一个自定义的Repository类,继承FOS的基础Repository:
// src/Repository/Elastica/ProductRepository.php namespace App\Repository\Elastica; use FOS\ElasticaBundle\Repository; class ProductRepository extends Repository { /** * 根据关键词搜索产品 */ public function search(string $query): array { $boolQuery = new \Elastica\Query\BoolQuery(); // 匹配多个字段,支持模糊搜索 $matchQuery = new \Elastica\Query\MultiMatch(); $matchQuery->setQuery($query); $matchQuery->setFields(['name', 'description']); $boolQuery->addMust($matchQuery); $searchQuery = new \Elastica\Query($boolQuery); return $this->find($searchQuery); } }
然后在fos_elastica配置里指定这个自定义Repository:
# config/packages/fos_elastica.yaml # ... 其他配置 persistence: # ... 已有配置 repository: App\Repository\Elastica\ProductRepository
3. 修改SonataAdmin类,替换搜索逻辑
现在要让SonataAdmin的列表页和搜索功能走ES而不是Doctrine。咱们可以重写Admin类里的createQuery方法,或者配置datagrid的数据源。
方法一:重写createQuery(完全控制查询)
在你的ProductAdmin类里注入Elastica的Repository,然后重写createQuery:
// src/Admin/ProductAdmin.php namespace App\Admin; use Sonata\AdminBundle\Admin\AbstractAdmin; use Sonata\AdminBundle\Datagrid\DatagridMapper; use Sonata\AdminBundle\Datagrid\ListMapper; use App\Repository\Elastica\ProductRepository; use Sonata\DoctrineORMAdminBundle\Datagrid\ProxyQuery\ArrayQuery; class ProductAdmin extends AbstractAdmin { private $elasticaProductRepo; // 注入Elastica Repository public function __construct(string $code, string $class, string $baseControllerName, ProductRepository $elasticaProductRepo) { parent::__construct($code, $class, $baseControllerName); $this->elasticaProductRepo = $elasticaProductRepo; } // 重写createQuery,替换成ES查询 protected function createQuery($context = 'list') { // 获取用户输入的搜索关键词 $datagrid = $this->getDatagrid(); $filters = $datagrid->getFilters(); $searchQuery = ''; if (isset($filters['name']) && $filters['name']->hasValue()) { $searchQuery = $filters['name']->getValue(); } // 调用自定义的ES搜索方法 $results = $this->elasticaProductRepo->search($searchQuery); // 将ES结果转换成Sonata需要的QueryInterface $query = new ArrayQuery($results); return $query; } // 配置列表字段 protected function configureListFields(ListMapper $listMapper) { $listMapper ->add('id') ->add('name') ->add('price') ->add('_action', null, [ 'actions' => [ 'show' => [], 'edit' => [], ] ]); } // 配置搜索过滤器 protected function configureDatagridFilters(DatagridMapper $datagridMapper) { $datagridMapper ->add('name'); // 对应ES里的name字段 } }
方法二:使用Sonata的Elastica集成(更简洁)
如果你不想自己写太多查询逻辑,可以先安装SonataElasticaBundle:
composer require sonata-project/elastica-bundle
然后在Admin类里配置:
// src/Admin/ProductAdmin.php namespace App\Admin; use Sonata\AdminBundle\Admin\AbstractAdmin; use Sonata\ElasticaBundle\Datagrid\ProxyQuery; use Sonata\ElasticaBundle\Filter\StringFilter; class ProductAdmin extends AbstractAdmin { protected function createQuery($context = 'list') { $query = new ProxyQuery($this->getModelManager()->createQuery()); return $query; } protected function configureDatagridFilters(DatagridMapper $datagridMapper) { $datagridMapper ->add('name', StringFilter::class, [ 'field_options' => [ 'field' => ['name', 'description'] // 多字段搜索 ] ]); } }
4. 同步数据到Elasticsearch
最后别忘了把现有实体数据同步到ES索引:
php bin/console fos:elastica:populate
这样之后,你在SonataAdmin后台的搜索就会走Elasticsearch啦,性能肯定会提升不少!如果遇到字段映射或者查询的问题,检查下ES的索引结构和你的配置是否对应就好~
内容的提问来源于stack exchange,提问作者hero dev
相关产品推荐
相关产品推荐

