<?php namespace IQDEV\ElasticSearchTests\Filter; use IQDEV\ElasticSearch\Converter\CriteriaToEsRequest; use IQDEV\ElasticSearch\Criteria; use IQDEV\ElasticSearch\Filter\Collection\FilterGroupCollection; use IQDEV\ElasticSearch\Filter\Field; use IQDEV\ElasticSearch\Filter\Filter; use IQDEV\ElasticSearch\Filter\FilterOperator; use IQDEV\ElasticSearch\Filter\FilterType; use IQDEV\ElasticSearch\Filter\Value\FilterKeyword; use IQDEV\ElasticSearch\Filter\Value\FilterNumber; use IQDEV\ElasticSearch\Query\SearchQuery; use IQDEV\ElasticSearchTests\AbstractTestCase; use IQDEV\ElasticSearchTests\Helpers\FormatData; use IQDEV\ElasticSearchTests\Service\SearchClient; /** * Тестирование агрегирующих функций */ class QueryTest extends AbstractTestCase { public function testFilterChangeFromPostToQuery() { $filter = [ 'category' => [ 'key' => 'category_id', 'value' => 'shoes', ], 'brand' => [ 'key' => 'brand', 'value' => 'nike', ], 'price' => [ 'key' => 'price', 'max' => 100.0, 'min' => 10.0, ] ]; $criteria = new Criteria(); $filterCollectionCategory = new FilterGroupCollection([ new Filter( new Field($filter['category']['key']), new FilterOperator(FilterOperator::EQ), new FilterKeyword($filter['category']['value']) ) ]); $filterCollectionCategory->setFilterType(FilterType::query()); $criteria->filters()->add($filterCollectionCategory); $filterCollectionBrand = new FilterGroupCollection([ new Filter( new Field($filter['brand']['key']), new FilterOperator(FilterOperator::EQ), new FilterKeyword($filter['brand']['value']) ) ]); $filterCollectionPrice = new FilterGroupCollection([ new Filter( new Field($filter['price']['key']), new FilterOperator(FilterOperator::LT), new FilterNumber($filter['price']['min']) ), new Filter( new Field($filter['price']['key']), new FilterOperator(FilterOperator::GT), new FilterNumber($filter['price']['max']) ), ]); // Формирование фильтра для post $criteriaPost = clone $criteria; $criteriaPost->filters()->add(clone $filterCollectionPrice); $criteriaPost->filters()->add(clone $filterCollectionBrand); // Формирование фильтра для query $criteriaQuery = clone $criteria; $filterTypeQuery = FilterType::query(); $filterCollectionPrice->setFilterType($filterTypeQuery); $filterCollectionBrand->setFilterType($filterTypeQuery); $criteriaQuery->filters()->add(clone $filterCollectionPrice); $criteriaQuery->filters()->add(clone $filterCollectionBrand); // Получение классов с данными для запроса в es $criteriaToEsRequest = new CriteriaToEsRequest(); $requestPost = $criteriaToEsRequest->fromCriteria($criteriaPost); $requestQuery = $criteriaToEsRequest->fromCriteria($criteriaQuery); $expectedFilter = [ [ "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'] ] ] ] ] ] ] ] ] ] ] ] ], [ "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'], ] ] ] ] ] ] ] ] ] ] ] ] ] ]; $expected = [ "query" => [ "bool" => [ "must" => [ [ "term" => [ "category_id" => $filter['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']), new FilterOperator(FilterOperator::LT), new FilterNumber($filter['price']['min']) ), new Filter( new Field($filter['price']['key']), new FilterOperator(FilterOperator::GT), new FilterNumber($filter['price']['max']) ), ]); $criteria->filters()->add($filterCollectionPrice); $filterCollectionQueryPrice = new FilterGroupCollection([ new Filter( new Field($filter['price']['key']), new FilterOperator(FilterOperator::LT), new FilterNumber($filter['price']['lower']) ), ]); $filterCollectionQueryPrice->setFilterType(FilterType::query()); $criteria->filters()->add($filterCollectionQueryPrice); $criteriaToEsRequest = new CriteriaToEsRequest(); $request = $criteriaToEsRequest->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']), new FilterOperator(FilterOperator::GTE), new FilterNumber($filter['price']['min']) ) ]); $criteria->filters()->add($filterCollectionPrice); $filterCollectionQueryPrice = new FilterGroupCollection([ new Filter( new Field($filter['price']['key']), new FilterOperator(FilterOperator::GTE), new FilterNumber($filter['price']['lower']) ), ]); $filterCollectionQueryPrice->setFilterType(FilterType::query()); $criteria->filters()->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)); } }