Lower-level API to build concept queries

Removes wrapPrivateFieldConceptQueries().
The goal is to wrap text and concept queries with a single call to wrapPrivateFieldQueries().
This commit is contained in:
Mathieu Darse
2015-08-26 19:10:27 +02:00
parent 9d6a428208
commit d6a44c8a52
3 changed files with 64 additions and 69 deletions

View File

@@ -13,6 +13,7 @@ abstract class AbstractTermNode extends Node implements TermInterface
protected $text; protected $text;
protected $context; protected $context;
private $concepts = []; private $concepts = [];
private $pruned_concepts;
public function __construct($text, Context $context = null) public function __construct($text, Context $context = null)
{ {
@@ -22,56 +23,70 @@ abstract class AbstractTermNode extends Node implements TermInterface
public function setConcepts(array $concepts) public function setConcepts(array $concepts)
{ {
$this->pruned_concepts = null;
$this->concepts = $concepts; $this->concepts = $concepts;
} }
private function getPrunedConcepts()
{
if ($this->pruned_concepts === null) {
$this->pruned_concepts = Concept::pruneNarrowConcepts($this->concepts);
}
return $this->pruned_concepts;
}
protected function buildConceptQueries(QueryContext $context) protected function buildConceptQueries(QueryContext $context)
{ {
$concepts = Concept::pruneNarrowConcepts($this->concepts); if (!$this->getPrunedConcepts()) {
if (!$concepts) {
return []; return [];
} }
$query_builder = function (array $fields) use ($concepts) { $query_builder = function (array $fields) {
$index_fields = []; $concept_queries = $this->buildConceptQueriesForFields($fields);
foreach ($fields as $field) {
$index_fields[] = $field->getConceptPathIndexField();
}
if (!$index_fields) {
return null;
}
$query = null; $query = null;
foreach ($concepts as $concept) { foreach ($concept_queries as $concept_query) {
$concept_query = [
'multi_match' => [
'fields' => $index_fields,
'query' => $concept->getPath()
]
];
$query = QueryHelper::applyBooleanClause($query, 'should', $concept_query); $query = QueryHelper::applyBooleanClause($query, 'should', $concept_query);
} }
return $query; return $query;
}; };
$query = $query_builder($context->getUnrestrictedFields()); $queries = $this->buildConceptQueriesForFields($context->getUnrestrictedFields());
if (
isset($query['bool']) &&
isset($query['bool']['should']) &&
count($query) === 1 /* no options or must(_not) clauses */
) {
$queries = $query['bool']['should'];
} else {
$queries = [$query];
}
$private_fields = $context->getPrivateFields(); $private_fields = $context->getPrivateFields();
foreach (QueryHelper::wrapPrivateFieldConceptQueries($private_fields, $query_builder) as $private_field_query) { foreach (QueryHelper::wrapPrivateFieldQueries($private_fields, $query_builder) as $private_field_query) {
$queries[] = $private_field_query; $queries[] = $private_field_query;
} }
return $queries; return $queries;
} }
protected function buildConceptQueriesForFields(array $fields)
{
$concepts = $this->getPrunedConcepts();
if (!$concepts) {
return [];
}
$index_fields = [];
foreach ($fields as $field) {
$index_fields[] = $field->getConceptPathIndexField();
}
if (!$index_fields) {
return [];
}
$queries = [];
foreach ($concepts as $concept) {
$queries[] = [
'multi_match' => [
'fields' => $index_fields,
'query' => $concept->getPath()
]
];
}
return $queries;
}
public function getValue() public function getValue()
{ {
return $this->text; return $this->text;

View File

@@ -59,19 +59,31 @@ class TextNode extends AbstractTermNode implements ContextAbleInterface
}; };
$unrestricted_fields = $context->getUnrestrictedFields(); $unrestricted_fields = $context->getUnrestrictedFields();
$unrestricted_fields = Field::filterByValueCompatibility($unrestricted_fields, $this->text); $compatible_unrestricted_fields = Field::filterByValueCompatibility($unrestricted_fields, $this->text);
$query = $query_builder($unrestricted_fields); $query = $query_builder($compatible_unrestricted_fields);
$private_fields = $context->getPrivateFields(); $private_fields = $context->getPrivateFields();
$private_fields = Field::filterByValueCompatibility($private_fields, $this->text); $compatible_private_fields = Field::filterByValueCompatibility($private_fields, $this->text);
foreach (QueryHelper::wrapPrivateFieldQueries($private_fields, $query_builder) as $private_field_query) { foreach (QueryHelper::wrapPrivateFieldQueries($compatible_private_fields, $query_builder) as $private_field_query) {
$query = QueryHelper::applyBooleanClause($query, 'should', $private_field_query); $query = QueryHelper::applyBooleanClause($query, 'should', $private_field_query);
} }
$concept_queries = $this->buildConceptQueries($context); // Concepts handling
$concept_queries = $this->buildConceptQueriesForFields($unrestricted_fields);
foreach ($concept_queries as $concept_query) { foreach ($concept_queries as $concept_query) {
$query = QueryHelper::applyBooleanClause($query, 'should', $concept_query); $query = QueryHelper::applyBooleanClause($query, 'should', $concept_query);
} }
$query_builder = function (array $fields) {
$concept_queries = $this->buildConceptQueriesForFields($fields);
$query = null;
foreach ($concept_queries as $concept_query) {
$query = QueryHelper::applyBooleanClause($query, 'should', $concept_query);
}
return $query;
};
foreach (QueryHelper::wrapPrivateFieldQueries($private_fields, $query_builder) as $private_field_query) {
$query = QueryHelper::applyBooleanClause($query, 'should', $private_field_query);
}
return $query; return $query;
} }

View File

@@ -29,10 +29,10 @@ class QueryHelper
foreach ($fields_map as $hash => $fields) { foreach ($fields_map as $hash => $fields) {
// Right to query on a private field is dependant of document collection // Right to query on a private field is dependant of document collection
// Here we make sure we can only match on allowed collections // Here we make sure we can only match on allowed collections
$queries[] = self::restrictQueryToCollections( $query = $query_builder($fields);
$query_builder($fields), if ($query !== null) {
$collections_map[$hash] $queries[] = self::restrictQueryToCollections($query, $collections_map[$hash]);
); }
} }
return $queries; return $queries;
@@ -61,38 +61,6 @@ class QueryHelper
return implode('|', $collections); return implode('|', $collections);
} }
/**
* @todo Factor with wrapPrivateFieldQueries()
*/
public static function wrapPrivateFieldConceptQueries(array $fields, \Closure $query_builder)
{
// We make a boolean clause for each collection set to shrink query size
// (instead of a clause for each field, with his collection set)
$fields_map = [];
$collections_map = [];
foreach ($fields as $field) {
$collections = $field->getDependantCollections();
$hash = self::hashCollections($collections);
$collections_map[$hash] = $collections;
if (!isset($fields_map[$hash])) {
$fields_map[$hash] = [];
}
// Merge fields with others having the same collections
$fields_map[$hash][] = $field;
}
$queries = [];
foreach ($fields_map as $hash => $fields) {
// Right to query on a private field is dependant of document collection
// Here we make sure we can only match on allowed collections
$query = $query_builder($fields);
$query = self::restrictQueryToCollections($query, $collections_map[$hash]);
$queries[] = $query;
}
return $queries;
}
/** /**
* Apply conjunction or disjunction between a query and a sub query clause * Apply conjunction or disjunction between a query and a sub query clause
* *