diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php index 82ff905e90..eaf94815f6 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php @@ -373,7 +373,7 @@ class ElasticSearchEngine implements SearchEngineInterface ]; $query_filters = $this->createQueryFilters($options); - $acl_filters = $this->createACLFilters(); + $acl_filters = $this->createACLFilters($options); $ESQuery = ['filtered' => ['query' => $ESQuery]]; @@ -411,13 +411,16 @@ class ElasticSearchEngine implements SearchEngineInterface // document that shouldn't be displayed can go this far. $agg = []; $agg['terms']['field'] = $field->getIndexField(true); + if(($size = $field->getFacetsSize()) !== null) { + $agg['terms']['size'] = $size; + } $aggs[$name] = AggregationHelper::wrapPrivateFieldAggregation($field, $agg); } return $aggs; } - private function createACLFilters() + private function createACLFilters(SearchEngineOptions $options) { // No ACLs if no user if (false === $this->app->getAuthenticator()->isAuthenticated()) { @@ -440,7 +443,7 @@ class ElasticSearchEngine implements SearchEngineInterface // Get intersection between collection ACLs and collection chosen by end user $aclRules = $this->getACLsByCollection($flagRules, $flagNamesMap); - return $this->buildACLsFilters($aclRules); + return $this->buildACLsFilters($aclRules, $options); } private function createQueryFilters(SearchEngineOptions $options) @@ -601,11 +604,20 @@ class ElasticSearchEngine implements SearchEngineInterface return $rules; } - private function buildACLsFilters(array $aclRules) + private function buildACLsFilters(array $aclRules, SearchEngineOptions $options) { $filters = []; + $collections = $options->getCollections(); + + $collectionsWoRules = []; + $collectionsWoRules['terms']['base_id'] = []; foreach ($aclRules as $baseId => $flagsRules) { + if(!array_key_exists($baseId, $collections)) { + // no need to add a filter if the collection is not searched + continue; + } + $ruleFilter = $baseFilter = []; // filter on base @@ -626,9 +638,27 @@ class ElasticSearchEngine implements SearchEngineInterface $ruleFilter['bool']['must'][] = $flagFilter; } - $filters[] = $ruleFilter; + if(count($ruleFilter['bool']['must']) > 1) { + // some rules found, add the filter + $filters[] = $ruleFilter; + } + else { + // no rules for this collection, add it to the 'simple' list + $collectionsWoRules['terms']['base_id'][] = $baseId; + } + } + if (count($collectionsWoRules['terms']['base_id']) > 0) { + // collections w/o rules : add a simple list ? + if(count($filters) > 0) { // no need to add a big 'should' filter only on collections + $filters[] = $collectionsWoRules; + } } - return ['bool' => ['should' => $filters]]; + if(count($filters) > 0) { + return ['bool' => ['should' => $filters]]; + } + else { + return []; + } } } diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Structure/Field.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Structure/Field.php index 4221bf0249..ab47caeeda 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Structure/Field.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Structure/Field.php @@ -19,7 +19,8 @@ class Field private $type; private $is_searchable; private $is_private; - private $is_facet; + private $is_facet; // bool return facet for this field + private $facets_size; // number of facets to return (null=default, 0= no limit) private $thesaurus_roots; private $used_by_collections; @@ -36,10 +37,19 @@ class Field $roots = null; } + // for phraseanet : 0=no facets (also returns isAggregable()=false) ; -1=all facets + $facet = $field->isAggregable(); + $facets_size = $field->getAggregableSize(); + if($facets_size === -1) { + // for ES 0=all facets + $facets_size = 0; + } + return new self($field->get_name(), $type, [ 'searchable' => $field->is_indexable(), 'private' => $field->isBusiness(), - 'facet' => $field->isAggregable(), + 'facet' => $facet, + 'facets_size' => $facets_size, 'thesaurus_roots' => $roots, 'used_by_collections' => $databox->get_collection_unique_ids() ]); @@ -68,6 +78,7 @@ class Field $this->is_searchable = \igorw\get_in($options, ['searchable'], true); $this->is_private = \igorw\get_in($options, ['private'], false); $this->is_facet = \igorw\get_in($options, ['facet'], false); + $this->facets_size = $this->is_facet ? \igorw\get_in($options, ['facets_size'], null) : 0; // here 0 means "no facets" $this->thesaurus_roots = \igorw\get_in($options, ['thesaurus_roots'], null); $this->used_by_collections = \igorw\get_in($options, ['used_by_collections'], []); @@ -86,6 +97,7 @@ class Field 'searchable' => $this->is_searchable, 'private' => $this->is_private, 'facet' => $this->is_facet, + 'facets_size' => $this->facets_size, 'thesaurus_roots' => $this->thesaurus_roots, 'used_by_collections' => $this->used_by_collections ]); @@ -171,6 +183,11 @@ class Field return $this->is_facet; } + public function getFacetsSize() + { + return $this->facets_size; + } + public function hasConceptInference() { return $this->thesaurus_roots !== null; diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Structure/GlobalStructure.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Structure/GlobalStructure.php index d4f6f16712..4bfc5d97fd 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Structure/GlobalStructure.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Structure/GlobalStructure.php @@ -71,6 +71,9 @@ final class GlobalStructure implements Structure return $this->private; } + /** + * @return Field[] + */ public function getFacetFields() { return $this->facets; diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Structure/LimitedStructure.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Structure/LimitedStructure.php index 4727b4c1c0..db0256e105 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Structure/LimitedStructure.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Structure/LimitedStructure.php @@ -41,6 +41,9 @@ final class LimitedStructure implements Structure return $this->limit($this->structure->getPrivateFields()); } + /** + * @return Field[] + */ public function getFacetFields() { return $this->limit($this->structure->getFacetFields()); diff --git a/lib/classes/databox/field.php b/lib/classes/databox/field.php index 5af451eca0..bf7609fb58 100644 --- a/lib/classes/databox/field.php +++ b/lib/classes/databox/field.php @@ -194,6 +194,11 @@ class databox_field implements cache_cacheableInterface return $this->aggregable != 0; } + public function getAggregableSize() + { + return $this->aggregable; + } + public function hydrate(Application $app) { $this->app = $app;