1

我使用 fos:elastica 从事 Symfony2 项目。用户可以喜欢和关注他们喜欢的地方。默认情况下,当用户喜欢某个地方时,我们会自动添加“关注”操作。

所以首先,我将这两个动作保存在数据库(doctrine2)中。我的数据已正确保存在数据库中。

当我使用索引“user_action”进行 ES 查询时,我会得到与地点相关的所有操作(之前的喜欢和关注)。

但是当我对索引“地方”做同样的事情时,我只会得到第一个动作(比如)。

似乎 ES 无法更新建议对象中的 userAction。

另一方面,如果我删除保留“以下”操作的查询(在喜欢之后自动添加)并且我进行第二次调用(通过 api),我的操作将保存在数据库中并在适当的位置更新对象。

希望有人能理解我所说的和我尝试做的 ^^

映射

地方

place:
     mappings:
      id:
       type: integer
      userAction:
       type: nested
       properties:
         userId:
           type: integer
         userActionTypeId:
           type: integer
         userActionType:
           type: nested
           properties:
             name:
               type: string

用户操作

user_action:
    mappings:
          userId:
            type: integer
          placeId: ~
          place:
            type: nested
            properties:
              id:
                type: integer
          userActionType:
            type: nested
            properties:
              name: ~

听众

服务

`fos_elastica.listener.place.user_action`:
   class: API\Rest\v1\PlaceBundle\EventListener\ElasticaUserActionListener
   arguments:
       - @fos_elastica.object_persister.search.user_action
       - ['postPersist', 'postRemove']
       - @fos_elastica.indexable
   calls:
       - [ setContainer, ['@service_container', @fos_elastica.object_persister.search.place ] ]
   tags:
       - { name: 'doctrine.event_subscriber' }

班级

<?php

namespace API\Rest\v1\PlaceBundle\EventListener;

use Doctrine\Common\EventArgs;
use FOS\ElasticaBundle\Doctrine\Listener as BaseListener;
use FOS\ElasticaBundle\Persister\ObjectPersister;
use Symfony\Component\DependencyInjection\ContainerInterface;
use API\Rest\v1\UserActionBundle\Entity\UserAction;

class ElasticaUserActionListener extends BaseListener
{
    private $container;
    private $objectPersisterSuggestion;

    public function setContainer(ContainerInterface $container, ObjectPersister $objectPersisterSuggestion)
    {
        $this->container                 = $container;
        $this->objectPersisterPlace = $objectPersisterPlace;
    }

    public function postPersist(EventArgs $eventArgs)
    {
        $entity = $eventArgs->getEntity();

        if ($entity instanceof UserAction) {
            $this->scheduledForInsertion[] = $entity;
            $this->objectPersisterPlace->replaceOne($entity->getPlace());
        }
    }

    public function postRemove(EventArgs $eventArgs)
    {
        $entity = $eventArgs->getEntity();

        if ($entity instanceof UserAction) {
            $this->scheduleForDeletion($entity);
            $this->objectPersisterPlace->replaceOne($entity->getPlace());
        }
    }
}

当前结果

使用嵌套对象 userAction 获取位置 (#320)

query : http://localhost:9200/search/place/_search
"hits" : [
    {
        "_index" : "search",
        "_type" : "place",
        "_id" : "320",
        "_score" : 5.7004805,
        "_source":{
            "userAction":[
                {
                    "userActionType":{
                        "name":"like"
                    },
                    "userActionTypeId":3,
                    "userId":3
                }
            ]
        }
    }
]

获取与具有 id #320 的地点相关的用户操作

query : http://localhost:9200/search/user_action/_search
"hits" : [
    {
        "_index" : "search",
        "_type" : "user_action",
        "_id" : "50",
        "_score" : 5.7004805,
        "_source" : {
            "userId" : 4,
            "placeId" : 320,
            "userActionType" : {
                "name" : "following"
                }
            }
    },
    {
        "_index" : "search",
        "_type" : "user_action",
        "_id" : "49",
        "_score" : 5.402646,
        "_source" : {
            "userId" : 4,
            "placeId" : 320,
            "userActionType" : {
                "name" : "like"
            }
        }
    }
]

更新(解决方案)

我终于找到了正确的方法。我过早地刷新数据。

我替换了这个错误的代码

$em = $this->getEntityManager();
$em->persist($like);
$em->flush();  

$em = $this->getEntityManager();
$em->persist($following);
$em->flush();  

经过

$em = $this->getEntityManager();
$em->persist($like);
$em->persist($following);  
$em->flush();

它正在工作!!!!

希望这可以帮助某人。

4

1 回答 1

0

使用 FOSElasticaBundle 3.0.x 对我来说最适合更新嵌套对象的方法如下:

将此添加到app/config/config.yml

services:
    # your other services

    fos_elastica.listener.search.user_action:
        class: "Acme\Bundle\UserActionBundle\EventListener\ElasticaUserActionListener"
        arguments:
            - @fos_elastica.object_persister.search.user_action
            - ['postPersist', 'postInsert', 'postUpdate', 'preRemove']
            - @fos_elastica.indexable
            - { indexName: 'user_action', typeName: 'userAction'}
        calls:
            - [ setContainer, ['@service_container', @fos_elastica.object_persister.search.user_action] ]
        tags:
            - { name: 'doctrine.event_subscriber' }

然后在中创建一个新文件UserActionBundle\EventListener

# Acme\Bundle\UserActionBundle\EventListener\ElasticaUserActionListener.php
namespace Acme\Bundle\UserActionBundle\EventListener;

use Doctrine\Common\EventArgs;
use FOS\ElasticaBundle\Doctrine\Listener as BaseListener;
use FOS\ElasticaBundle\Persister\ObjectPersister;
use Symfony\Component\DependencyInjection\ContainerInterface;

class ElasticaUserActionListener extends BaseListener
{
    private $container;
    private $objectPersisterUserAction;

    public function setContainer(ContainerInterface $container, ObjectPersister $objectPersisterUserAction)
    {
        $this->container = $container;
        $this->objectPersisterUserAction = $objectPersisterUserAction;
    }

    public function getClassAccessorArray() {
        return [
            [
                'accessor' => 'getPlace', 
                'class' => new Place(),
            ],
            // add more child objects here, if needed
        ];
    }

    public function postPersist(EventArgs $args)
    {
        $entity = $args->getEntity();

        foreach ($this->getClassAccessorArray() as $accessorArray) {
            $class = $accessorArray['class'];
            $accessorFunction = $accessorArray['accessor'];
            if ($entity instanceof $class) {
                $this->scheduledForInsertion[] = $entity;
                $this->objectPersisterUserAction->insertOne($entity->$accessorFunction());
                break;
            }
        }
    }

    public function postUpdate(EventArgs $args)
    {
        $entity = $args->getEntity();

        foreach ($this->getClassAccessorArray() as $accessorArray) {
            $class = $accessorArray['class'];
            $accessorFunction = $accessorArray['accessor'];
            if ($entity instanceof $class) {
                $this->scheduledForUpdate[] = $entity;
                $this->objectPersisterUserAction->replaceOne($entity->$accessorFunction());
                break;
            }
        }
    }

    public function preRemove(EventArgs $eventArgs) {
        $entity = $eventArgs->getEntity();

        foreach ($this->getClassAccessorArray() as $accessorArray) {
            $class = $accessorArray['class'];
            $accessorFunction = $accessorArray['accessor'];

            if ($entity instanceof $class) {
                $this->scheduleForDeletion($entity);
                $this->objectPersisterUserAction->deleteOne($entity->$accessorFunction());
            }
        }
    }
}

当直接更新嵌套对象时,这可以很好地更新 ElasticSearch 的索引。Place在您的情况下,由于您在s 和s之间具有有效的双向关系UserAction,您可以扩展 Listener 类以处理这两个类,或者只是复制并创建一个ElasticaPlaceListener服务和类。

于 2015-06-10T00:24:22.983 回答