1

私は fos:elastica を使用して Symfony2 プロジェクトに取り組んでいます。ユーザーは好きな場所をいいねしてフォローすることができます。デフォルトでは、ユーザーが場所を気に入ると、「フォロー中」アクションが自動的に追加されます。

まず最初に、これら 2 つのアクションをデータベース (doctrine2) に永続化します。私のデータはdbに正しく保存されています。

インデックス「user_action」を使用して ES クエリを作成すると、場所に関連するすべてのアクションが取得されます (前のようなものと次のもの)。

しかし、インデックス「場所」で同じことを行うと、最初のアクション(いいね)しか得られません。

ES は、提案オブジェクトで userAction を更新できていないようです。

一方、「次の」アクションを永続化するクエリを削除し (いいねの後に自動的に追加されます)、(API を介して) 2 番目の呼び出しを行うと、アクションは db に保存され、代わりにオブジェクトも更新されます。

誰かが私が言ったことと私がやろうとしていることを理解してくれることを願っています^^

マッピング

場所

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 のインデックスを更新するのにうまく機能します。あなたの場合、Places とUserActions の間に事実上双方向の関係があるため、 Listener クラスを拡張して両方のクラスを処理するか、ElasticaPlaceListenerサービスとクラスを複製して作成することもできます。

于 2015-06-10T00:24:22.983 に答える