Search code examples
phpsymfonyelasticsearchfoselasticabundle

Optional Self-Parent Relation in Elasticsearch


I have a Symfony2 project, and I'm trying to implement a search feature using Elasticsearch.

My problem is, I need to index an entity with an optional self-relation. It means that my Item entity has a "parent" field, referencing another Item.

In order to make the search, I want to create filters on that "parent" field. Is my Item.parent is NULL ? for instance.

So, I am using the FosElasticaBundle.

Here is my mapping :

    types:
    Item:
        mappings:
            name:
            children:
                type: object
                _parent:
                    type: Item
            parent:
                type: object
        _routing:
            required: false
        _parent:
            type : Item
            identifier: id
            property : parent
        persistence:
            ...
            model_to_elastica_transformer:
                service: core.transformer.item

And the transformer does :

$document = new Document();

if (!is_null($item->getParent())) {
    $document->setParent($item->getParent()->getId());
} else {
     $document->setParent(null);
}

return $document;

And, the problem occurs when I try to create my index ( php app/console fos:elastica:populate )

This command returns the following ResponseException:

index: /traveler/Item caused RoutingMissingException[routing is required for [traveler]/[Item]/[null]] 

Do you have any idea why this isn't working ? And is this the good way to do it ?

Thanks,


Solution

  • Since my needs are pretty simple in this case, we managed to solve this problem.

    Configuration

    Instead of using the _parent field in config, I used a nested property.

    Item:
        mappings:
            children:
                type: "nested"
                properties:
                    name: ~
            parent:
                type: "object"
    

    This is a tree, so children and parent properties are both Item. I needed to create requess with filter on the parent value (is null, is equals something...)

    Request

    So, I used the \Elasitca\Filter\Nested.

    For instance, when I need to exclude some resultats based on children's user and language, I can do the following :

    $nestedFilter  = new Nested();
    $boolFilter    = new Bool();
    $boolAndFilter = new BoolAnd();
    $boolAndFilter
        ->setFilters(array(
            new Term(array("children.user.id" => $this->getClient()->getId())),
            new Term(array("children.other" => $language))
        ))
    ;
    
    $nestedFilter
        ->setFilter($boolAndFilter)
        ->setPath('children')
    ;
    
    $query = new Filtered(
        $query,
        new BoolNot($boolFilter->addMust($nestedFilter))
    );
    

    I think this solution has limitation (for multi-level parenting I assume), but for this need, it works.