Source of file QueryGeneratorTest.php
Size: 27,289 Bytes - Last Modified: 2021-12-23T10:58:34+00:00
/var/www/docs.ssmods.com/process/src/tests/long/QueryGeneratorTest.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757 | <?php use \SilverStripe\Elastica\QueryGenerator; /** * Test query generation. */ class QueryGeneratorTest extends ElasticsearchTestBase { public static $fixture_file = 'elastica/tests/lotsOfPhotos.yml'; public static $ignoreFixtureFileFor = array('testToQuoted*'); public function testTextOnly() { $qg = new QueryGenerator(); $qg->setQueryText('New Zealand'); $qg->setFields(null); $qg->setSelectedFilters(null); //As the query is not empty it should not matter whether or not the show results for empty //query flag is set or not - test with true and false $qg->setShowResultsForEmptyQuery(false); $qs = array('query_string' => array('query' => 'New Zealand', 'lenient' => true)); $expected = array( 'query' => $qs, 'size' => 10, 'from' => 0, 'suggest' => $this->getDefaultSuggest('New Zealand'), ); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); $qg->setShowResultsForEmptyQuery(true); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); } /** * @param string $queryText */ private function getDefaultSuggest($queryText) { return array( 'query-phrase-suggestions' => array( 'phrase' => array( 'field' => '_all', 'size' => 4, 'highlight' => array( 'pre_tag' => '<strong class="hl">', 'post_tag' => '</strong>', ), ), 'text' => $queryText, ), ); } public function testEmptyTextShowNone() { $qg = new QueryGenerator(); $qg->setQueryText(''); $qg->setFields(null); $qg->setSelectedFilters(null); $qg->setShowResultsForEmptyQuery(false); $qs = array('query_string' => array('query' => '', 'lenient' => true)); $expected = array( 'query' => $qs, 'size' => 10, 'from' => 0, 'suggest' => $this->getDefaultSuggest(''), ); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); } public function testEmptyTextShowAll() { $qg = new QueryGenerator(); $qg->setQueryText(''); $qg->setFields(null); $qg->setSelectedFilters(null); $qg->setShowResultsForEmptyQuery(true); //In order to show all results an empty query works, //e.g. curl -XGET 'http://localhost:9200/elastica_ss_module_test_en_us/_search?pretty' $expected = array( 'size' => 10, 'from' => 0, 'suggest' => $this->getDefaultSuggest(''), ); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); } public function testMultiMatchWithText() { $qg = new QueryGenerator(); $qg->setQueryText('New Zealand'); $fields = array('Title' => 1, 'Description' => 1); $qg->setFields($fields); $qg->setSelectedFilters(null); $qg->setClasses('FlickrPhotoTO'); //As the query is not empty it should not matter whether or not the show results for empty //query flag is set or not - test with true and false $qg->setShowResultsForEmptyQuery(false); $qs = array('multi_match' => array( 'fields' => array('Title', 'Title.*', 'Description', 'Description.*'), 'type' => 'most_fields', 'query' => 'New Zealand', 'lenient' => true, ), ); $expected = array( 'query' => $qs, 'size' => 10, 'from' => 0, 'suggest' => $this->getDefaultSuggest('New Zealand'), ); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); $qg->setShowResultsForEmptyQuery(true); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); } public function testMultiMatchWithNoText() { $qg = new QueryGenerator(); $qg->setQueryText(''); $fields = array('Title' => 1, 'Description' => 1); $qg->setFields($fields); $qg->setSelectedFilters(null); $qg->setClasses('FlickrPhotoTO'); //As the query is not empty it should not matter whether or not the show results for empty //query flag is set or not - test with true and false //Case of empty query, do not show results $qg->setShowResultsForEmptyQuery(false); $qs = array( 'multi_match' => array( 'fields' => array('Title', 'Title.*', 'Description', 'Description.*'), 'type' => 'most_fields', 'query' => '', 'lenient' => true, ), ); $expected = array( 'query' => $qs, 'size' => 10, 'from' => 0, 'suggest' => $this->getDefaultSuggest(''), ); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); // Now the case of empty query and show results $qg->setShowResultsForEmptyQuery(true); unset($expected['query']); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); } // ---- tests with aggregations ---- public function testEmptyTextShowNoResultsWithAggregations() { $this->assertFalse(false, 'This is not possible - an empty query returns 0 docs and 0 aggregations'); } /* Test aggregations with and without text query */ public function testTextShowResultsWithAggregations() { $qg = new QueryGenerator(); $qg->setQueryText(''); $qg->setFields(null); $qg->setSelectedFilters(null); $qg->setShowResultsForEmptyQuery(true); $qg->setQueryResultManipulator('FlickrPhotoTOElasticaSearchHelper'); $aggs = $this->baseAggs(); //tests are complete $expected = array( 'aggs' => $aggs, 'size' => 10, 'from' => 0, 'sort' => array('TakenAt' => 'desc'), 'suggest' => $this->getDefaultSuggest(''), ); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); $qg->setQueryText('New Zealand'); unset($expected['sort']); $expected['query'] = array('query_string' => array('query' => 'New Zealand', 'lenient' => true)); $expected['suggest'] = $this->getDefaultSuggest('New Zealand'); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); $qg->setShowResultsForEmptyQuery(false); $qg->setQueryText('New Zealand'); $expected['query'] = array('query_string' => array('query' => 'New Zealand', 'lenient' => true)); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); } /* Should generate this working query: curl -XGET 'http://localhost:9200/elastica_ss_module_test_en_us/_search?pretty' -d ' { "query": { "filtered": { "filter": { "term": { "ISO": 400 } } } }, "aggs": { "Aperture": { "terms": { "field": "Aperture", "size": 0, "order": { "_term": "asc" } } }, "ShutterSpeed": { "terms": { "field": "ShutterSpeed", "size": 0, "order": { "_term": "asc" } } }, "FocalLength35mm": { "terms": { "field": "FocalLength35mm", "size": 0, "order": { "_term": "asc" } } }, "ISO": { "terms": { "field": "ISO", "size": 0, "order": { "_term": "asc" } } }, "Aspect": { "range": { "field": "AspectRatio", "ranges": [{ "from": 1.0e-7, "to": 0.3, "key": "Panoramic" }, { "from": 0.3, "to": 0.9, "key": "Horizontal" }, { "from": 0.9, "to": 1.2, "key": "Square" }, { "from": 1.2, "to": 1.79, "key": "Vertical" }, { "from": 1.79, "to": 10000000, "key": "Tallest" }] } } }, "size": 10, "from": 0 } ' */ public function testTextOneFilterAggregate() { $qg = new QueryGenerator(); $qg->setQueryText(''); $qg->setFields(null); $filters = array('ISO' => 400); $qg->setSelectedFilters($filters); $qg->setShowResultsForEmptyQuery(true); $qg->setQueryResultManipulator('FlickrPhotoTOElasticaSearchHelper'); $aggs = $this->baseAggs(); //FIXME - query needs removed in this case, leave as a reminder for now until //tests are complete $expected = array( 'aggs' => $aggs, 'size' => 10, 'from' => 0, 'query' => array( 'filtered' => array( 'filter' => array('term' => array('ISO' => 400)), ), ), 'sort' => array('TakenAt' => 'desc'), 'suggest' => $this->getDefaultSuggest(''), ); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); $qg->setQueryText('New Zealand'); unset($expected['sort']); // use query text search relevance for sorting, ie default Elasticsearch $expected['query']['filtered']['query']['query_string'] = array('query' => 'New Zealand', 'lenient' => true); $expected['suggest'] = $this->getDefaultSuggest('New Zealand'); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); } public function testTextTwoFilterAggregate() { $qg = new QueryGenerator(); $qg->setQueryText(''); $qg->setFields(null); $filters = array('ISO' => 400, 'Aspect' => 'Square'); $qg->setSelectedFilters($filters); $qg->setShowResultsForEmptyQuery(true); $qg->setQueryResultManipulator('FlickrPhotoTOElasticaSearchHelper'); $aggs = $this->baseAggs(); //FIXME - query needs removed in this case, leave as a reminder for now until //tests are complete $expected = array( 'aggs' => $aggs, 'size' => 10, 'from' => 0, 'query' => array( 'filtered' => array( 'filter' => array('and' => array( 0 => array('term' => array('ISO' => 400)), 1 => array('range' => array( 'AspectRatio' => array( 'gte' => '0.9', 'lt' => '1.2', ), )), ), ), ), ), 'sort' => array('TakenAt' => 'desc'), 'suggest' => $this->getDefaultSuggest(''), ); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); $qg->setQueryText('New Zealand'); unset($expected['sort']); // use query text search relevance for sorting, ie default Elasticsearch $expected['query']['filtered']['query']['query_string'] = array('query' => 'New Zealand', 'lenient' => true); $expected['suggest'] = $this->getDefaultSuggest('New Zealand'); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); } public function testTextThreeFilterAggregate() { $qg = new QueryGenerator(); $qg->setQueryText(''); $qg->setFields(null); $filters = array('ISO' => 400, 'Aspect' => 'Square', 'Aperture' => 5.6); $qg->setSelectedFilters($filters); $qg->setShowResultsForEmptyQuery(true); $qg->setQueryResultManipulator('FlickrPhotoTOElasticaSearchHelper'); $aggs = $this->baseAggs(); //FIXME - query needs removed in this case, leave as a reminder for now until //tests are complete $expected = array( 'aggs' => $aggs, 'size' => 10, 'from' => 0, 'query' => array( 'filtered' => array('filter' => array('and' => array( 0 => array('term' => array('ISO' => 400)), 1 => array('range' => array( 'AspectRatio' => array( 'gte' => '0.9', 'lt' => '1.2', ), )), 2 => array('term' => array('Aperture' => 5.6)), ), )), ), 'sort' => array('TakenAt' => 'desc'), 'suggest' => $this->getDefaultSuggest(''), ); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); $qg->setQueryText('New Zealand'); unset($expected['sort']); // use query text search relevance for sorting, ie default Elasticsearch $expected['query']['filtered']['query']['query_string'] = array('query' => 'New Zealand', 'lenient' => true); $expected['suggest'] = $this->getDefaultSuggest('New Zealand'); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); } public function testMultiMatchOneFilterAggregate() { $qg = new QueryGenerator(); $qg->setQueryText(''); $qg->setFields(array('Title' => 2, 'Content' => 1)); $filters = array('ISO' => 400); $qg->setSelectedFilters($filters); $qg->setShowResultsForEmptyQuery(true); $qg->setQueryResultManipulator('FlickrPhotoTOElasticaSearchHelper'); $aggs = $this->baseAggs(); //FIXME - query needs removed in this case, leave as a reminder for now until //tests are complete $expected = array( 'aggs' => $aggs, 'size' => 10, 'from' => 0, 'query' => array( 'filtered' => array( 'filter' => array('term' => array('ISO' => 400)), ), ), 'sort' => array('TakenAt' => 'desc'), 'suggest' => $this->getDefaultSuggest(''), ); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); $qg->setQueryText('New Zealand'); unset($expected['sort']); // use relevance of search sorting $expected['query']['filtered']['query']['multi_match'] = array( 'query' => 'New Zealand', 'lenient' => true, 'fields' => array('Title^2', 'Title.*^2', 'Content', 'Content.*'), 'type' => 'most_fields', ); $expected['suggest'] = $this->getDefaultSuggest('New Zealand'); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); } public function testMultiMatchTwoFilterAggregate() { $qg = new QueryGenerator(); $qg->setQueryText(''); $qg->setFields(array('Title' => 2, 'Content' => 1)); $filters = array('ISO' => 400, 'Aspect' => 'Square'); $qg->setSelectedFilters($filters); $qg->setShowResultsForEmptyQuery(true); $qg->setQueryResultManipulator('FlickrPhotoTOElasticaSearchHelper'); $aggs = $this->baseAggs(); //FIXME - query needs removed in this case, leave as a reminder for now until //tests are complete $expected = array( 'aggs' => $aggs, 'size' => 10, 'from' => 0, 'query' => array( 'filtered' => array( 'filter' => array('and' => array( 0 => array('term' => array('ISO' => 400)), 1 => array('range' => array( 'AspectRatio' => array( 'gte' => '0.9', 'lt' => '1.2', ), )), ), ), ), ), 'sort' => array('TakenAt' => 'desc'), 'suggest' => $this->getDefaultSuggest(''), ); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); $qg->setQueryText('New Zealand'); unset($expected['sort']); // use relevance of search sorting $expected['query']['filtered']['query']['multi_match'] = array( 'query' => 'New Zealand', 'lenient' => true, 'fields' => array('Title^2', 'Title.*^2', 'Content', 'Content.*'), 'type' => 'most_fields', ); $expected['suggest'] = $this->getDefaultSuggest('New Zealand'); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); } public function testMultiMatchThreeFilterAggregate() { $qg = new QueryGenerator(); $qg->setQueryText(''); $qg->setFields(array('Title' => 2, 'Content' => 1)); $filters = array('ISO' => 400, 'Aspect' => 'Square', 'Aperture' => 5.6); $qg->setSelectedFilters($filters); $qg->setShowResultsForEmptyQuery(true); $qg->setQueryResultManipulator('FlickrPhotoTOElasticaSearchHelper'); $aggs = $this->baseAggs(); //FIXME - query needs removed in this case, leave as a reminder for now until //tests are complete $expected = array( 'aggs' => $aggs, 'size' => 10, 'from' => 0, 'query' => array( 'filtered' => array('filter' => array('and' => array( 0 => array('term' => array('ISO' => 400)), 1 => array('range' => array( 'AspectRatio' => array( 'gte' => '0.9', 'lt' => '1.2', ), )), 2 => array('term' => array('Aperture' => 5.6)), ), )), ), 'sort' => array('TakenAt' => 'desc'), 'suggest' => $this->getDefaultSuggest(''), ); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); $qg->setQueryText('New Zealand'); unset($expected['sort']); $expected['query']['filtered']['query']['multi_match'] = array( 'query' => 'New Zealand', 'lenient' => true, 'fields' => array('Title^2', 'Title.*^2', 'Content', 'Content.*'), 'type' => 'most_fields', ); $expected['suggest'] = $this->getDefaultSuggest('New Zealand'); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); } // ---- tests for field array to elasticsearch syntax public function testConvertWeightedFieldsForElasticaUnaryStrings() { $qg = new QueryGenerator(); $qg->setClasses('FlickrPhotoTO'); $fields = array('Title' => 1, 'Description' => 1); $expected = array('Title', 'Title.*', 'Description', 'Description.*'); $this->assertEquals($expected, $qg->convertWeightedFieldsForElastica($fields)); } public function testConvertWeightedFieldsForElasticaMultipleStrings() { $qg = new QueryGenerator(); $qg->setClasses('FlickrPhotoTO'); $fields = array('Title' => 2, 'Description' => 1); $expected = array('Title^2', 'Title.*^2', 'Description', 'Description.*'); $this->assertEquals($expected, $qg->convertWeightedFieldsForElastica($fields)); } public function testConvertWeightedFieldsForElasticaTestNonString() { $qg = new QueryGenerator(); $qg->setClasses('FlickrPhotoTO'); $fields = array('Aperture' => 2, 'FocalLength35mm' => 1); $expected = array('Aperture^2', 'FocalLength35mm'); $this->assertEquals($expected, $qg->convertWeightedFieldsForElastica($fields)); } public function testConvertWeightedFieldsForElasticaNonExistent() { $qg = new QueryGenerator(); $qg->setClasses('FlickrPhotoTO'); $fields = array('Aperture' => 2, 'FocalLength35mm' => 1, 'Wibble' => 2); try { $this->assertEquals('This test should fail', $qg->convertWeightedFieldsForElastica($fields)); $this->fail('An exception should have been thrown as the field Wibble does not exist'); } catch (Exception $e) { $this->assertEquals('Field Wibble does not exist', $e->getMessage()); } } public function testSearchFieldsMappingForClasses() { $qg = new QueryGenerator(); $qg->setClasses('FlickrPhotoTO,Page'); $fields = array('Title' => 2, 'Description' => 1); $expected = array('Title^2', 'Title.*^2', 'Description', 'Description.*'); $this->assertEquals($expected, $qg->convertWeightedFieldsForElastica($fields)); $qg->setClasses(array('FlickrPhotoTO', 'Page')); $this->assertEquals($expected, $qg->convertWeightedFieldsForElastica($fields)); } public function testSearchFieldsMappingForClassesCaching() { QueryGenerator::resetCacheHitCounter(); $cache = SS_Cache::factory('elasticsearch'); // Previous tests may have altered this so start from a known position $cache->remove('SEARCHABLE_FIELDS_FlickrPhotoTO_Page'); $qg = new QueryGenerator(); $qg->setClasses('FlickrPhotoTO,Page'); $fields = array('Title' => 2, 'Description' => 1); $expected = array('Title^2', 'Title.*^2', 'Description', 'Description.*'); $this->assertEquals($expected, $qg->convertWeightedFieldsForElastica($fields)); //Execute a 2nd time $this->assertEquals($expected, $qg->convertWeightedFieldsForElastica($fields)); //Check for cache hit $this->assertEquals(1, QueryGenerator::getCacheHitCounter()); //Execute a 3rd time $this->assertEquals($expected, $qg->convertWeightedFieldsForElastica($fields)); //Check for cache hit $this->assertEquals(2, QueryGenerator::getCacheHitCounter()); } public function testSearchFieldsMappingForSiteTree() { $qg = new QueryGenerator(); $qg->setClasses(null); // select all of site tree classes $fields = array('Title' => 2, 'Content' => 1); $expected = array('Title^2', 'Title.*^2', 'Content', 'Content.*'); $this->assertEquals($expected, $qg->convertWeightedFieldsForElastica($fields)); $qg->setClasses(array('FlickrPhotoTO', 'Page')); $this->assertEquals($expected, $qg->convertWeightedFieldsForElastica($fields)); } public function testPagination() { $qg = new QueryGenerator(); $qg->setQueryText('New Zealand'); $qg->setFields(null); $qg->setSelectedFilters(null); $qg->setPageLength(12); $qg->setStart(24); //As the query is not empty it should not matter whether or not the show results for empty //query flag is set or not - test with true and false $qg->setShowResultsForEmptyQuery(false); $this->assertEquals(false, $qg->getShowResultsForEmptyQuery()); $qs = array('query_string' => array('query' => 'New Zealand', 'lenient' => true)); $expected = array( 'query' => $qs, 'size' => 12, 'from' => 24, 'suggest' => $this->getDefaultSuggest('New Zealand'), ); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); $qg->setShowResultsForEmptyQuery(true); $this->assertEquals(true, $qg->getShowResultsForEmptyQuery()); $this->assertEquals($expected, $qg->generateElasticaQuery()->toArray()); } /** * Get the basic aggregates that should be returned for the augmenter being tested. * * @return array array of aggregations. Tweak these in tests and assert as required. */ private function baseAggs() { $result = array(); $result['Aperture'] = array( 'terms' => array( 'field' => 'Aperture', 'size' => 0, 'order' => array('_term' => 'asc'), ), ); $result['ShutterSpeed'] = array( 'terms' => array( 'field' => 'ShutterSpeed', 'size' => 0, 'order' => array('_term' => 'asc'), ), ); $result['FocalLength35mm'] = array( 'terms' => array( 'field' => 'FocalLength35mm', 'size' => 0, 'order' => array('_term' => 'asc'), ), ); $result['ISO'] = array( 'terms' => array( 'field' => 'ISO', 'size' => 0, 'order' => array('_term' => 'asc'), ), ); $ranges = array(); $ranges[0] = array('from' => '1.0E-7', 'to' => '0.3', 'key' => 'Panoramic'); $ranges[1] = array('from' => '0.3', 'to' => '0.9', 'key' => 'Horizontal'); $ranges[2] = array('from' => '0.9', 'to' => '1.2', 'key' => 'Square'); $ranges[3] = array('from' => '1.2', 'to' => '1.79', 'key' => 'Vertical'); $ranges[4] = array('from' => '1.79', 'to' => '10000000', 'key' => 'Tallest'); $result['Aspect'] = array( 'range' => array( 'field' => 'AspectRatio', 'ranges' => $ranges, ), ); return $result; } // ---- tests for the toQuotedCSV function ---- public function testToQuotedCSVFromString() { $expected = "'Bangkok','Nonthaburi','Saraburi','Chiang Mai'"; $items = 'Bangkok,Nonthaburi,Saraburi,Chiang Mai'; $quoted = QueryGenerator::convertToQuotedCSV($items); $this->assertEquals($expected, $quoted); } public function testToQuotedCSVFromArray() { $expected = "'Bangkok','Nonthaburi','Saraburi','Chiang Mai'"; $items = array('Bangkok', 'Nonthaburi', 'Saraburi', 'Chiang Mai'); $quoted = QueryGenerator::convertToQuotedCSV($items); $this->assertEquals($expected, $quoted); } public function testToQuotedCSVEmptyString() { $quoted = QueryGenerator::convertToQuotedCSV(''); $this->assertEquals('', $quoted); } public function testToQuotedCSVEmptyArray() { $quoted = QueryGenerator::convertToQuotedCSV(array()); $this->assertEquals('', $quoted); } public function testToQuotedCSVNull() { $quoted = QueryGenerator::convertToQuotedCSV(null); $this->assertEquals('', $quoted); } } |