PHRAS-2009_Geo-operator_MASTER

add the "geolocation="lat lon distance" query
This commit is contained in:
Jean-Yves Gaulier
2018-05-17 21:13:28 +02:00
parent 1dcc579cfe
commit 1e64eb7a42
5 changed files with 101 additions and 6 deletions

View File

@@ -27,11 +27,16 @@ class EqualExpression extends Node
throw new QueryException(sprintf('Value "%s" for key "%s" is not valid.', $this->value, $this->key));
}
$query = [
'term' => [
$this->key->getIndexField($context, true) => $this->value
]
];
if(method_exists($this->key, "buildQuery")) {
$query = $this->key->buildQuery($this->value, $context);
}
else {
$query = [
'term' => [
$this->key->getIndexField($context, true) => $this->value
]
];
}
if ($this->key instanceof QueryPostProcessor) {
return $this->key->postProcessQuery($query, $context);

View File

@@ -0,0 +1,75 @@
<?php
namespace Alchemy\Phrasea\SearchEngine\Elastic\AST\KeyValue;
use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryContext;
class GeolocationKey implements Key
{
const TYPE_GEOLOCATION = 'geolocation';
private $type;
private $key;
private $matcher = '/^(-?\\d*(\\.\\d*)?)[\\s]+(-?\\d*(\\.\\d*)?)[\\s]+(\\d*(\\.\\d*)?)(\\D*)$/';
private $units = [
'mi', 'miles',
'yd', 'yards',
'ft', 'feet',
'in', 'inch',
'km', 'kilometers',
'm', 'meters',
'cm', 'centimeters',
'mm', 'millimeters',
'NM', 'nmi', 'nauticalmiles',
];
public static function geolocation()
{
return new self(self::TYPE_GEOLOCATION, 'geolocation');
}
public function buildQuery($value, QueryContext $context)
{
$matches = [];
if(preg_match($this->matcher, trim($value), $matches) === 1) {
$lat = $matches[1];
$lon = $matches[3];
$dst = $matches[5];
$uni = trim($matches[7]);
if(in_array($uni, $this->units)) {
return [
'geo_distance' => [
'distance' => $dst . $uni,
'location' => [
'lat' => $lat,
'lon' => $lon
]
]
];
}
}
return null;
}
private function __construct($type, $key)
{
$this->type = $type;
$this->key = $key;
}
public function getIndexField(QueryContext $context, $raw = false)
{
return $this->key;
}
public function isValueCompatible($value, QueryContext $context)
{
return preg_match($this->matcher, trim($value), $matches) === 1;
}
public function __toString()
{
return $this->type;
}
}

View File

@@ -28,6 +28,7 @@ class NodeTypes
const FLAG = '#flag';
const NATIVE_KEY = '#native_key';
const TIMESTAMP_KEY = '#timestamp_key';
const GEOLOCATION_KEY = '#geolocation_key';
// Token types for leaf nodes
const TOKEN_WORD = 'word';
const TOKEN_QUOTED_STRING = 'quoted';

View File

@@ -108,6 +108,9 @@ class QueryVisitor implements Visit
case NodeTypes::TIMESTAMP_KEY:
return $this->visitTimestampKeyNode($element);
case NodeTypes::GEOLOCATION_KEY:
return $this->visitGeolocationKeyNode($element);
case NodeTypes::METADATA_KEY:
return new AST\KeyValue\MetadataKey($this->visitString($element));
@@ -337,6 +340,11 @@ class QueryVisitor implements Visit
});
}
private function visitGeolocationKeyNode(TreeNode $node)
{
return AST\KeyValue\GeolocationKey::geolocation();
}
private function visitNativeKeyNode(TreeNode $node)
{
$this->assertChildrenCount($node, 1);