Skip to content
Snippets Groups Projects
QueryTest.php 23.96 KiB
<?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));
    }
}