FOSElacticaBundle: failed to parse [geo_bbox] query. unexpected field [gte] [reason: all shards failed]

223 Views Asked by At

I use FOSElasticaBundle's GeoBoundingBox [1] class to successfully populate a map of users in a given area. Now I want to add a criterion in order to only map users who were active within the last 10 minutes. So I add a mapping in fos_elastica.yml like

types:
    user:
        mappings:
            id: ~
            username: ~
            firstName: ~
            lastName: ~
            email: ~
            location:
                type: geo_point
            lastActivityAt:
                type: date
...

I run fos:elastica:reset and fos:elastica:populate, just to be sure I have current results. Those commands run successfully. So far so good, I also clear the Symfony cache. I then add the following logic in the controller that I'm hitting with an AJAX call

$query = new GeoBoundingBox(
            'location',
            array(
                //top_left
                array(
                   'lat' => $data['north'],
                   'lon' => $data['west']
                ),
                //bottom_right
                array(
                    'lat' => $data['south'],
                    'lon' => $data['east']
                )
            )
        );

$earlier = new \DateTime('10 minutes ago');
$query->addParam('lastActivityAt', ['gte' => $earlier]);

$result = $this->get('fos_elastica.finder.app.user')->find($query);
...

That's where the trouble starts. I refresh the map in the browser, and in the network inspector, I now get the following error

failed to parse [geo_bbox] query. unexpected field [gte] [reason: all shards failed]

I'm clearly doing something wrong here. I don't know much about Elasticsearch. How can I correctly use Param::addParam() to set this up?

[1] https://github.com/FriendsOfSymfony/FOSElasticaBundle

1

There are 1 best solutions below

3
Joe - Check out my books On BEST ANSWER

As the error message suggests, you cannot add a datetime range query to a geo_bounding_box query. You'll need to wrap both in a so-called boolean query.

You'd need something along the lines of:

$boolQuery = new \Elastica\Query\BoolQuery();

$bboxQuery = new GeoBoundingBox(
            'location',
            array(
                //top_left
                array(
                   'lat' => $data['north'],
                   'lon' => $data['west']
                ),
                //bottom_right
                array(
                    'lat' => $data['south'],
                    'lon' => $data['east']
                )
            )
        );
$boolQuery->addMust($bboxQuery);

$rangeQuery = new Elastica\Query\Range();
        $earlier = new \DateTime('2 hours ago');
        $earlierString = substr($earlier->format(DateTimeInterface::ISO8601), 0, -5);
        $timeZone = substr($earlier->format(DateTimeInterface::ISO8601), -5, 5);
        $rangeQuery->addField(
            'lastActivityAt',
            [
                'time_zone'=> $timeZone,
                'gte' => $earlierString,
                'lte' => 'now'
            ]
        );
$boolQuery->addMust($rangeQuery);

$result = $this->get('fos_elastica.finder.app.user')->find($boolQuery);