From 1123fd5032ce15e65ea1e88c7a56fe64cf1a44a7 Mon Sep 17 00:00:00 2001 From: tatiana-yan Date: Thu, 14 Jun 2018 17:06:58 +0300 Subject: [PATCH] [search] Fix category recognition for multiple words category synonyms --- indexer/categories_holder.hpp | 10 +++++ search/geocoder.cpp | 8 ++-- search/processor.cpp | 10 ++++- .../search_integration_tests/smoke_test.cpp | 8 +--- search/utils.hpp | 40 ++++++++++++------- 5 files changed, 47 insertions(+), 29 deletions(-) diff --git a/indexer/categories_holder.hpp b/indexer/categories_holder.hpp index 9feff6dd4b..6439ab2797 100644 --- a/indexer/categories_holder.hpp +++ b/indexer/categories_holder.hpp @@ -99,6 +99,16 @@ public: } } + template + void ForEachNameAndType(ToDo && toDo) const + { + for (auto const & p : m_type2cat) + { + for (auto const & synonym : p.second->m_synonyms) + toDo(synonym, p.first); + } + } + template void ForEachNameByType(uint32_t type, ToDo && toDo) const { diff --git a/search/geocoder.cpp b/search/geocoder.cpp index dba373ea2a..597a39abf5 100644 --- a/search/geocoder.cpp +++ b/search/geocoder.cpp @@ -459,8 +459,7 @@ void Geocoder::SetParamsForCategorialSearch(Params const & params) m_tokenRequests.clear(); m_prefixTokenRequest.Clear(); - ASSERT_EQUAL(m_params.GetNumTokens(), 1, ()); - ASSERT(!m_params.IsPrefixToken(0), ()); + ASSERT(!m_params.LastTokenIsPrefix(), ()); LOG(LDEBUG, (static_cast(m_params))); } @@ -782,12 +781,11 @@ void Geocoder::MatchCategories(BaseContext & ctx, bool aroundPivot) if (!GetTypeInGeocoding(ctx, featureId, type)) return; - EmitResult(ctx, m_context->GetId(), featureId, type, TokenRange(0, 1), nullptr /* geoParts */, + EmitResult(ctx, m_context->GetId(), featureId, type, TokenRange(0, ctx.m_numTokens), nullptr /* geoParts */, true /* allTokensUsed */); }; - // By now there's only one token and zero prefix tokens. - // Its features have been retrieved from the search index + // Features have been retrieved from the search index // using the exact (non-fuzzy) matching and intersected // with viewport, if needed. Every such feature is relevant. features.ForEach(emit); diff --git a/search/processor.cpp b/search/processor.cpp index f4223fd93c..b992e63c86 100644 --- a/search/processor.cpp +++ b/search/processor.cpp @@ -503,12 +503,18 @@ void Processor::InitParams(QueryParams & params) const params.GetTypeIndices(i).push_back(index); }; auto const tokenSlice = QuerySliceOnRawStrings(m_tokens, m_prefix); + vector types; bool const isCategorialRequest = - IsCategorialRequest(tokenSlice, GetCategoryLocales(), m_categories); + FillCategories(tokenSlice, GetCategoryLocales(), m_categories, types); params.SetCategorialRequest(isCategorialRequest); if (isCategorialRequest) { - ForEachCategoryType(tokenSlice, addCategorySynonyms); + for (auto const type : types) + { + uint32_t const index = c.GetIndexForType(type); + for (size_t i = 0; i < tokenSlice.Size(); ++i) + params.GetTypeIndices(i).push_back(index); + } } else { diff --git a/search/search_integration_tests/smoke_test.cpp b/search/search_integration_tests/smoke_test.cpp index 3df27d240c..9d46fef26c 100644 --- a/search/search_integration_tests/smoke_test.cpp +++ b/search/search_integration_tests/smoke_test.cpp @@ -194,16 +194,10 @@ UNIT_CLASS_TEST(SmokeTest, CategoriesTest) {"internet_access", "wlan"}, {"office"}, {"shop"}, - {"shop", "butcher"}, - {"shop", "florist"}, - {"shop", "greengrocer"}, - {"shop", "optician"}, {"place", "continent"}, {"place", "region"}, {"event", "fc2018_city"}, - {"sponsored", "holiday"}, - {"railway", "level_crossing"}, - {"highway", "rest_area"}}; + {"sponsored", "holiday"}}; set badTypes; for (auto const & tags : badTags) badTypes.insert(classif().GetTypeByPath(tags)); diff --git a/search/utils.hpp b/search/utils.hpp index 584362df81..0e913653f2 100644 --- a/search/utils.hpp +++ b/search/utils.hpp @@ -77,31 +77,41 @@ void ForEachCategoryTypeFuzzy(StringSliceBase const & slice, Locales const & loc } } -// Returns whether the request specified by |slice| is categorial -// in any of the |locales|. We expect that categorial requests should +// Returns |true| and fills |types| if request specified by |slice| is categorial +// in any of the |locales| and |false| otherwise. We expect that categorial requests should // mostly arise from clicking on a category button in the UI. // It is assumed that typing a word that matches a category's name // and a space after it means that no errors were made. template -bool IsCategorialRequest(QuerySliceOnRawStrings const & slice, Locales const & locales, - CategoriesHolder const & catHolder) +bool FillCategories(QuerySliceOnRawStrings const & slice, Locales const & locales, + CategoriesHolder const & catHolder, std::vector & types) { - if (slice.Size() != 1 || slice.HasPrefixToken()) + types.clear(); + if (slice.HasPrefixToken()) return false; - bool found = false; - auto token = slice.Get(0); - catHolder.ForEachName([&](CategoriesHolder::Category::Name const & categorySynonym) { - if (!locales.Contains(static_cast(categorySynonym.m_locale))) - return; + catHolder.ForEachNameAndType( + [&](CategoriesHolder::Category::Name const & categorySynonym, uint32_t type) { + if (!locales.Contains(static_cast(categorySynonym.m_locale))) + return; - if (token != search::NormalizeAndSimplifyString(categorySynonym.m_name)) - return; + std::vector categoryTokens; + SplitUniString(search::NormalizeAndSimplifyString(categorySynonym.m_name), + MakeBackInsertFunctor(categoryTokens), search::Delimiters()); - found = true; - }); + if (slice.Size() != categoryTokens.size()) + return; - return found; + for (size_t i = 0; i < slice.Size(); ++i) + { + if (slice.Get(i) != categoryTokens[i]) + return; + } + + types.push_back(type); + }); + + return !types.empty(); } MwmSet::MwmHandle FindWorld(Index const &index,