<?php namespace IQDEV\ElasticSearchTests\Filter; use IQDEV\ElasticSearch\Config\BaseConfiguration; use IQDEV\ElasticSearch\Converter\Request\CriteriaToRequest; use IQDEV\ElasticSearch\Criteria\Criteria; use IQDEV\ElasticSearch\Criteria\Filter\Collection\FilterGroupCollection; use IQDEV\ElasticSearch\Criteria\Filter\Field; use IQDEV\ElasticSearch\Criteria\Filter\Filter; use IQDEV\ElasticSearch\Criteria\Filter\FilterOperator; use IQDEV\ElasticSearch\Criteria\Filter\FilterType; use IQDEV\ElasticSearch\Criteria\Filter\Value\FilterKeyword; use IQDEV\ElasticSearch\Criteria\Filter\Value\FilterNumber; use IQDEV\ElasticSearch\Criteria\Query\SearchQuery; use IQDEV\ElasticSearch\Criteria\Search\Search; use IQDEV\ElasticSearch\Document\Property\Property; use IQDEV\ElasticSearchTests\AbstractTestCase; use IQDEV\ElasticSearchTests\Helpers\FormatData; use IQDEV\ElasticSearchTests\Service\SearchClient; /** * Тестирование агрегирующих функций */ class QueryTest extends AbstractTestCase { public function testFilterChangeFromPostToQuery() { $search = [ 'category' => [ 'key' => 'category_id', 'value' => 'shoes', ], ]; $filter = [ 'brand' => [ 'key' => 'brand', 'value' => 'nike', ], 'price' => [ 'key' => 'price', 'max' => 100.0, 'min' => 10.0, ] ]; $criteria = new Criteria(); $criteria->getSearch()->add( new Search( new Property($search['category']['key']), $search['category']['value'], ), ); $filterCollectionCategory = new FilterGroupCollection(); $filterCollectionCategory->setFilterType(FilterType::QUERY); $criteria->getFilters()->add($filterCollectionCategory); $filterCollectionBrand = new FilterGroupCollection([ new Filter( new Field($filter['brand']['key']), FilterOperator::EQ, new FilterKeyword($filter['brand']['value']) ) ]); $filterCollectionPrice = new FilterGroupCollection([ new Filter( new Field($filter['price']['key']), FilterOperator::LT, new FilterNumber($filter['price']['min']) ), new Filter( new Field($filter['price']['key']), FilterOperator::GT, new FilterNumber($filter['price']['max']) ), ]); // Формирование фильтра для post $criteriaPost = clone $criteria; $criteriaPost->getFilters()->add(clone $filterCollectionPrice); $criteriaPost->getFilters()->add(clone $filterCollectionBrand); // Формирование фильтра для query $criteriaQuery = clone $criteria; $filterTypeQuery = FilterType::QUERY; $filterCollectionPrice->setFilterType($filterTypeQuery); $filterCollectionBrand->setFilterType($filterTypeQuery); $criteriaQuery->getFilters()->add(clone $filterCollectionPrice); $criteriaQuery->getFilters()->add(clone $filterCollectionBrand); // Получение классов с данными для запроса в es $criteriaToRequest = new CriteriaToRequest(new BaseConfiguration()); $requestPost = $criteriaToRequest->fromCriteria($criteriaPost); $requestQuery = $criteriaToRequest->fromCriteria($criteriaQuery); $expectedFilter = [ [ "nested" => [ "path" => "search_data", "query" => [ "bool" => [ "filter" => [ [ "nested" => [ "path" => "search_data.number_facet", "query" => [ "bool" => [ "filter" => [ [ "term" => [ "search_data.number_facet.facet_code" => $filter['price']['key'] ] ], [ "range" => [ "search_data.number_facet.facet_value" => [ "lt" => $filter['price']['min'], "gt" => $filter['price']['max'], ] ] ] ] ] ] ] ] ] ] ] ] ], [ "nested" => [ "path" => "search_data", "query" => [ "bool" => [ "filter" => [ [ "nested" => [ "path" => "search_data.keyword_facet", "query" => [ "bool" => [ "filter" => [ [ "term" => [ "search_data.keyword_facet.facet_code" => $filter['brand']['key'] ] ], [ "term" => [ "search_data.keyword_facet.facet_value" => $filter['brand']['value'] ] ] ] ] ] ] ] ] ] ] ] ], ]; $expected = [ "query" => [ "bool" => [ "must" => [ [ "term" => [ "category_id" => $search['category']['value'] ] ], ] ] ], ]; $this->assertArray( array_merge($expected, [ "query" => [ "bool" => [ "filter" => $expectedFilter, ] ] ]), $requestQuery->es(), 'query response' ); $this->assertArray( array_merge($expected, [ "post_filter" => [ "bool" => [ "filter" => $expectedFilter, ] ] ]), $requestPost->es(), 'post response' ); } public function testAddingASingleKeyFilterToPostAndQuery() { $filter = [ 'price' => [ 'key' => 'price', 'max' => 100.0, 'min' => 10.0, 'lower' => 0.0, ] ]; $criteria = new Criteria(); $filterCollectionPrice = new FilterGroupCollection([ new Filter( new Field($filter['price']['key']), FilterOperator::LT, new FilterNumber($filter['price']['min']) ), new Filter( new Field($filter['price']['key']), FilterOperator::GT, new FilterNumber($filter['price']['max']) ), ]); $criteria->getFilters()->add($filterCollectionPrice); $filterCollectionQueryPrice = new FilterGroupCollection([ new Filter( new Field($filter['price']['key']), FilterOperator::LT, new FilterNumber($filter['price']['lower']) ), ]); $filterCollectionQueryPrice->setFilterType(FilterType::QUERY); $criteria->getFilters()->add($filterCollectionQueryPrice); $criteriaToRequest = new CriteriaToRequest(new BaseConfiguration()); $request = $criteriaToRequest->fromCriteria($criteria); $expected = [ "post_filter" => [ "bool" => [ "filter" => [ 0 => [ "nested" => [ "path" => "search_data", "query" => [ "bool" => [ "filter" => [ 0 => [ "nested" => [ "path" => "search_data.number_facet", "query" => [ "bool" => [ "filter" => [ [ "term" => [ "search_data.number_facet.facet_code" => "price" ] ], [ "range" => [ "search_data.number_facet.facet_value" => [ "lt" => $filter['price']['min'], "gt" => $filter['price']['max'], ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ], "query" => [ "bool" => [ "filter" => [ 0 => [ "nested" => [ "path" => "search_data", "query" => [ "bool" => [ "filter" => [ 0 => [ "nested" => [ "path" => "search_data.number_facet", "query" => [ "bool" => [ "filter" => [ 0 => [ "term" => [ "search_data.number_facet.facet_code" => "price" ] ], 1 => [ "range" => [ "search_data.number_facet.facet_value" => [ "lt" => $filter['price']['lower'] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ]; $this->assertArray($expected, $request->es()); } public function testGlobalFilterPrice() { $filter = [ 'price' => [ 'key' => 'price', 'min' => 105, 'lower' => 103, ] ]; $criteria = new Criteria(); $filterCollectionPrice = new FilterGroupCollection([ new Filter( new Field($filter['price']['key']), FilterOperator::GTE, new FilterNumber($filter['price']['min']) ) ]); $criteria->getFilters()->add($filterCollectionPrice); $filterCollectionQueryPrice = new FilterGroupCollection([ new Filter( new Field($filter['price']['key']), FilterOperator::GTE, new FilterNumber($filter['price']['lower']) ), ]); $filterCollectionQueryPrice->setFilterType(FilterType::QUERY); $criteria->getFilters()->add($filterCollectionQueryPrice); $q = new SearchQuery($criteria); $handler = SearchClient::getInstance(); $result = $handler->handle($q)->result; $expected = [ 'hits' => [ 'h2', 'h3', 'p1', ], "facets" => [ 0 => [ "code" => "brand", "label" => null, "type" => "list", "items" => [ "list" => [ 0 => [ "label" => null, "value" => "nike", "count" => 1, "active" => true, ], 1 => [ "label" => null, "value" => "rebook", "count" => 2, "active" => true, ] ], "range" => [], ], ], 1 => [ "code" => "color", "label" => null, "type" => "list", "items" => [ "list" => [ 0 => [ "label" => null, "value" => "green", "count" => 0, "active" => false, ], 1 => [ "label" => null, "value" => "red", "count" => 0, "active" => false, ], 2 => [ "label" => null, "value" => "white", "count" => 3, "active" => true, ], ], "range" => [], ], ], 2 => [ "code" => "size", "label" => null, "type" => "list", "items" => [ "list" => [ 0 => [ "label" => null, "count" => 0, "value" => "43", "active" => false, ], 1 => [ "label" => null, "value" => "xl", "count" => 2, "active" => true, ], 2 => [ "label" => null, "value" => "xxl", "count" => 1, "active" => true, ], ], "range" => [], ], ], 3 => [ "code" => "price", "label" => null, "type" => "range", "items" => [ "list" => [], "range" => [ 0 => [ "label" => null, "count" => 3, "active" => true, "fullRange" => [ "min" => 103.0, "max" => 107.0, ], "activeRange" => [ "min" => 105.0, "max" => 107.0, ] ] ] ] ] ] ]; $this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result)); } public function testGlobalFilterMinPrice() { $filter = [ 'price' => [ 'key' => 'price', 'lower' => 103, ] ]; $criteria = new Criteria(); $filterCollectionQueryPrice = new FilterGroupCollection([ new Filter( new Field($filter['price']['key']), FilterOperator::GTE, new FilterNumber($filter['price']['lower']) ), ]); $filterCollectionQueryPrice->setFilterType(FilterType::QUERY); $criteria->getFilters()->add($filterCollectionQueryPrice); $q = new SearchQuery($criteria); $handler = SearchClient::getInstance(); $result = $handler->handle($q)->result; $expected = [ 'hits' => [ 's4', 'h1', 'h2', 'h3', 'p1', ], "facets" => [ 0 => [ "code" => "brand", "label" => null, "type" => "list", "items" => [ "list" => [ 0 => [ "label" => null, "value" => "nike", "count" => 3, "active" => true, ], 1 => [ "label" => null, "value" => "rebook", "count" => 2, "active" => true, ] ], "range" => [], ], ], 1 => [ "code" => "color", "label" => null, "type" => "list", "items" => [ "list" => [ 0 => [ "label" => null, "value" => "green", "count" => 1, "active" => true, ], 1 => [ "label" => null, "value" => "red", "count" => 1, "active" => true, ], 2 => [ "label" => null, "value" => "white", "count" => 3, "active" => true, ], ], "range" => [], ], ], 2 => [ "code" => "size", "label" => null, "type" => "list", "items" => [ "list" => [ 0 => [ "label" => null, "count" => 1, "value" => "43", "active" => true, ], 1 => [ "label" => null, "value" => "xl", "count" => 3, "active" => true, ], 2 => [ "label" => null, "value" => "xxl", "count" => 1, "active" => true, ], ], "range" => [], ], ], 3 => [ "code" => "price", "label" => null, "type" => "range", "items" => [ "list" => [], "range" => [ 0 => [ "label" => null, "count" => 5, "active" => true, "fullRange" => [ "min" => 103.0, "max" => 107.0, ], "activeRange" => [ "min" => 103.0, "max" => 107.0, ] ] ] ] ] ] ]; $this->assertEqualsCanonicalizing($expected, FormatData::formatDataWFacets($result)); } }