Как выполнять вложенные запросы с помощью Elastica Search и Symfony2

У меня есть объект рецепта, который имеет несколько тегов (сопоставление «многие ко многим»), и я хочу искать рецепты по тегам.

Вот мой объект Recipe:

/**
 * @ORM\Entity
 * @ORM\Table(name="recipes")
 * @ORM\HasLifecycleCallbacks
 * @ExclusionPolicy("all")
 */
class Recipe
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     * @Expose
     */
    protected $id;

    /**
     * @ORM\Column(type="string", length=150)
     * @Expose
     */
    protected $name;

    ...

    /**
     * @ORM\ManyToMany(targetEntity="RecipesTag", inversedBy="recipes")
     * @ORM\JoinTable(name="bind_recipes_tags",
     *      joinColumns={@ORM\JoinColumn(name="tag_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="recipe_id", referencedColumnName="id")}
     *      )
     */
    private $tags;

Вот моя конфигурация:

fos_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    serializer:
        callback_class: FOS\ElasticaBundle\Serializer\Callback
        serializer: serializer
    indexes:
        td:
            client: default
            types:
                Recipe:
                    mappings:
                        name: ~
                        ingredients: 
                            type: "nested"
                            properties:
                                name: ~
                        tags:
                            type: "nested"
                            properties:
                                name: ~
                                id : 
                                    type : integer
                        categories:
                            type: "nested"
                            properties:
                                name: ~
                                id : 
                                    type : integer

                    persistence:
                        driver: orm # orm, mongodb, propel are available
                        model:  ck\RecipesBundle\Entity\Recipe
                        repository: ck\RecipesBundle\Entity\RecipesRepository
                        provider: ~
                        listener: ~
                        finder: ~

Затем я добавил собственный репозиторий для выполнения поиска:

public function filterFind($searchText)
{
    $query_part = new \Elastica\Query\Bool();

    $nested = new \Elastica\Query\Nested();
    $nested->setQuery(new \Elastica\Query\Term(array('name' => array('value' => $searchText))));
    $nested->setPath('tags');
    $query_part->addShould($nested);

    return $this->find($query_part);
}

Затем я ищу так:

$repositoryManager = $this->get('fos_elastica.manager.orm');
$repository = $repositoryManager->getRepository('ckRecipesBundle:Recipe');

$recipes = $repository->filterFind('mytag');

Но я не получил никаких результатов, несмотря на то, что есть совпадающие результаты.

В гугле ответов не нашел. Кто-нибудь может мне помочь?


person Chiguicapa    schedule 24.06.2014    source источник
comment
ты решил это? ответ хороший?   -  person goto    schedule 16.03.2016


Ответы (2)


Вот ответ, как это сделать. Для меня это работает. http://obtao.com/blog/2014/04/elasticsearch-advanced-search-and-nested-objects/

По сути, вам нужно создать такой запрос:

{
    "query":{
        "filtered":{
            "query":{
                "query_string":{
                    "query":"*saf*"
                }
            },
            "filter":{
                "nested":{
                    "path":"categories",
                    "filter":{
                        "bool":{
                            "must": [{
                                "term":{
                                    "categories.id":1
                                }
                            }]
                        }
                    },
                    "query":{
                        "match":{
                            "id":1
                        }
                    }
                }
            }
        }
    }
} 

Для меня в PHP это выглядит так:

        $bool = new Filter\Bool();
        $bool->addMust(new Filter\Term(['categories.id' => $category->getId()]));

        $nested = new Filter\Nested();
        $nested->setPath("categories");
        $nested->setFilter($bool);

        $nested->setQuery($categoriesQuery);

        $queryObj = new Query\Filtered($queryObj, $nested);

Фильтр — Elastica\Filter, а запрос — Elastica\Query.

person krun    schedule 10.07.2014

Действительно, вы забыли определить фильтрованный запрос.

Это должно работать:

$nested->setQuery(new \Elastica\Query\Term(array('name' => array('value' => $searchText))));
$nested->setPath('tags');
$query_part->addShould($nested);

$query = new \Elastica\Query\Filtered($query_part/*, $filters // in case you had other filters*/);
return $this->find($query);
person GregOs    schedule 11.05.2016