Pass structure to query visitor & enable range generation for regular fields (equal expression)

This commit is contained in:
Mathieu Darse
2015-11-13 19:45:39 +01:00
parent ccc5315ad3
commit 3b2d6b05a0
6 changed files with 95 additions and 31 deletions

View File

@@ -24,6 +24,7 @@ use Alchemy\Phrasea\SearchEngine\Elastic\Indexer\TermIndexer;
use Alchemy\Phrasea\SearchEngine\Elastic\RecordHelper;
use Alchemy\Phrasea\SearchEngine\Elastic\Search\Escaper;
use Alchemy\Phrasea\SearchEngine\Elastic\Search\FacetsResponse;
use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryContextFactory;
use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryCompiler;
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\GlobalStructure;
use Alchemy\Phrasea\SearchEngine\Elastic\Thesaurus;
@@ -62,7 +63,7 @@ class SearchEngineServiceProvider implements ServiceProviderInterface
$app['search_engine.structure'],
$app['elasticsearch.client'],
$options->getIndexName(),
$app['locales.available'],
$app['query_context.factory'],
$app['elasticsearch.facets_response.factory'],
$options
);
@@ -181,6 +182,14 @@ class SearchEngineServiceProvider implements ServiceProviderInterface
);
});
$app['query_context.factory'] = $app->share(function ($app) {
return new QueryContextFactory(
$app['search_engine.structure'],
array_keys($app['locales.available']),
$app['locale']
);
});
$app['query_parser.grammar_path'] = function ($app) {
$configPath = ['registry', 'searchengine', 'query-grammar-path'];
$grammarPath = $app['conf']->get($configPath, 'grammar/query.pp');
@@ -197,6 +206,7 @@ class SearchEngineServiceProvider implements ServiceProviderInterface
$app['query_compiler'] = $app->share(function ($app) {
return new QueryCompiler(
$app['query_parser'],
$app['search_engine.structure'],
$app['thesaurus']
);
});

View File

@@ -20,6 +20,11 @@ class FieldKey implements Key, QueryPostProcessor
$this->name = $name;
}
public function getName()
{
return $this->name;
}
public function getIndexField(QueryContext $context, $raw = false)
{
return $this->getField($context)->getIndexField($raw);

View File

@@ -19,8 +19,8 @@ use Alchemy\Phrasea\SearchEngine\Elastic\Search\AggregationHelper;
use Alchemy\Phrasea\SearchEngine\Elastic\Search\FacetsResponse;
use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryCompiler;
use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryContext;
use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryContextFactory;
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Flag;
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\LimitedStructure;
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Structure;
use Alchemy\Phrasea\SearchEngine\SearchEngineInterface;
use Alchemy\Phrasea\SearchEngine\SearchEngineOptions;
@@ -48,12 +48,12 @@ class ElasticSearchEngine implements SearchEngineInterface
/** @var ElasticsearchOptions */
private $options;
public function __construct(Application $app, Structure $structure, Client $client, $indexName, array $locales, Closure $facetsResponseFactory, ElasticsearchOptions $options)
public function __construct(Application $app, Structure $structure, Client $client, $indexName, QueryContextFactory $context_factory, Closure $facetsResponseFactory, ElasticsearchOptions $options)
{
$this->app = $app;
$this->structure = $structure;
$this->client = $client;
$this->locales = array_keys($locales);
$this->context_factory = $context_factory;
$this->facetsResponseFactory = $facetsResponseFactory;
$this->options = $options;
@@ -62,6 +62,7 @@ class ElasticSearchEngine implements SearchEngineInterface
}
$this->indexName = $indexName;
}
public function getIndexName()
@@ -261,12 +262,7 @@ class ElasticSearchEngine implements SearchEngineInterface
public function query($string, $offset, $perPage, SearchEngineOptions $options = null)
{
$options = $options ?: new SearchEngineOptions();
$narrowToFields = array();
foreach($options->getFields() as $field) {
$narrowToFields[] = $field->get_name();
}
$context = $this->createQueryContext($options)->narrowToFields($narrowToFields);
$context = $this->context_factory->createContext($options);
/** @var QueryCompiler $query_compiler */
$query_compiler = $this->app['query_compiler'];
@@ -352,23 +348,6 @@ class ElasticSearchEngine implements SearchEngineInterface
];
}
/**
* @todo Move in search engine service provider
*/
private function createQueryContext(SearchEngineOptions $options)
{
return new QueryContext(
$this->getLimitedStructure($options),
$this->locales,
$this->app['locale']
);
}
private function getLimitedStructure(SearchEngineOptions $options)
{
return new LimitedStructure($this->structure, $options);
}
/**
* {@inheritdoc}
*/
@@ -455,7 +434,7 @@ class ElasticSearchEngine implements SearchEngineInterface
$base_facet_agg['terms']['field'] = 'type';
$aggs['Type'] = $base_facet_agg;
$structure = $this->getLimitedStructure($options);
$structure = $this->context_factory->getLimitedStructure($options);
foreach ($structure->getFacetFields() as $name => $field) {
// 2015-05-26 (mdarse) Removed databox filtering.
// It was already done by the ACL filter in the query scope, so no

View File

@@ -4,6 +4,7 @@ namespace Alchemy\Phrasea\SearchEngine\Elastic\Search;
use Alchemy\Phrasea\SearchEngine\Elastic\AST;
use Alchemy\Phrasea\SearchEngine\Elastic\Exception\QueryException;
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Structure;
use Alchemy\Phrasea\SearchEngine\Elastic\Thesaurus;
use Hoa\Compiler\Exception\Exception as CompilerException;
use Hoa\Compiler\Llk\Parser;
@@ -14,6 +15,7 @@ use Hoa\Visitor\Visit;
class QueryCompiler
{
private $parser;
private $structure;
private $thesaurus;
private static $leftAssociativeOperators = array(
@@ -22,9 +24,10 @@ class QueryCompiler
NodeTypes::EXCEPT_EXPR
);
public function __construct(Parser $parser, Thesaurus $thesaurus)
public function __construct(Parser $parser, Structure $structure, Thesaurus $thesaurus)
{
$this->parser = $parser;
$this->structure = $structure;
$this->thesaurus = $thesaurus;
}
@@ -54,7 +57,12 @@ class QueryCompiler
*/
public function parse($string, $postprocessing = true)
{
return $this->visitString($string, new QueryVisitor(), $postprocessing);
return $this->visitString($string, $this->createQueryVisitor(), $postprocessing);
}
private function createQueryVisitor()
{
return new QueryVisitor($this->structure);
}
public function dump($string, $postprocessing = true)

View File

@@ -0,0 +1,49 @@
<?php
namespace Alchemy\Phrasea\SearchEngine\Elastic\Search;
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\LimitedStructure;
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Structure;
use Alchemy\Phrasea\SearchEngine\SearchEngineOptions;
class QueryContextFactory
{
private $structure;
public function __construct(Structure $structure, array $locales, $current_locale)
{
$this->structure = $structure;
$this->locales = $locales;
$this->current_locale = $current_locale;
}
public function createContext(SearchEngineOptions $options = null)
{
$structure = $options
? $this->getLimitedStructure($options)
: $this->structure;
$context = new QueryContext($structure, $this->locales, $this->current_locale);
if ($options) {
$fields = $this->getSearchedFields($options);
$context = $context->narrowToFields($fields);
}
return $context;
}
private function getSearchedFields(SearchEngineOptions $options)
{
$fields = [];
foreach ($options->getFields() as $field) {
$fields[] = $field->get_name();
}
return $fields;
}
public function getLimitedStructure(SearchEngineOptions $options)
{
return new LimitedStructure($this->structure, $options);
}
}

View File

@@ -5,6 +5,7 @@ namespace Alchemy\Phrasea\SearchEngine\Elastic\Search;
use Alchemy\Phrasea\SearchEngine\Elastic\AST;
use Alchemy\Phrasea\SearchEngine\Elastic\Exception\Exception;
use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryHelper;
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Structure;
use Hoa\Compiler\Llk\TreeNode;
use Hoa\Visitor\Element;
use Hoa\Visitor\Visit;
@@ -12,6 +13,13 @@ use InvalidArgumentException;
class QueryVisitor implements Visit
{
private $structure;
public function __construct(Structure $structure)
{
$this->structure = $structure;
}
public function visit(Element $element, &$handle = null, $eldnah = null)
{
if (null !== $value = $element->getValue()) {
@@ -197,7 +205,12 @@ class QueryVisitor implements Visit
private function isDateKey(AST\KeyValue\Key $key)
{
return $key instanceof AST\KeyValue\TimestampKey;
if ($key instanceof AST\KeyValue\TimestampKey) {
return true;
} elseif ($key instanceof AST\KeyValue\FieldKey) {
return $this->structure->get($key->getName()) !== null;
}
return false;
}
private function visitTerm(Element $element)