diff options
author | mpimenov <mpimenov@users.noreply.github.com> | 2016-06-17 17:24:03 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-06-17 17:24:03 +0300 |
commit | 8811238c06e852feb49db747f61f00c0575dfb5a (patch) | |
tree | 905ae88c9a9151c27c053bef2d44121681428f6b /search | |
parent | 0b8e94adccd2da6019b6ff5512156e8b1d570123 (diff) | |
parent | 6334404df5a5133c81d24932d4683ac2069864d3 (diff) |
Merge pull request #3596 from ygorshenin/fix-streets-matching
[search] Fixed streets matching.
Diffstat (limited to 'search')
-rw-r--r-- | search/geocoder.cpp | 99 | ||||
-rw-r--r-- | search/geocoder.hpp | 4 | ||||
-rw-r--r-- | search/search_integration_tests/processor_test.cpp | 17 |
3 files changed, 85 insertions, 35 deletions
diff --git a/search/geocoder.cpp b/search/geocoder.cpp index 1f0ac2b8fa..550c104b5b 100644 --- a/search/geocoder.cpp +++ b/search/geocoder.cpp @@ -466,6 +466,8 @@ void Geocoder::SetParams(Params const & params) } } + LOG(LDEBUG, ("Tokens =", m_params.m_tokens)); + LOG(LDEBUG, ("Prefix tokens =", m_params.m_prefixTokens)); LOG(LDEBUG, ("Languages =", m_params.m_langs)); } @@ -1075,61 +1077,92 @@ void Geocoder::GreedilyMatchStreets() continue; // Here we try to match as many tokens as possible while - // intersection is a non-empty bit vector of streets. All tokens - // that are synonyms to streets are ignored. Moreover, each time - // a token that looks like a beginning of a house number is met, - // we try to use current intersection of tokens as a street layer - // and try to match buildings or pois. - unique_ptr<coding::CompressedBitVector> allFeatures; + // intersection is a non-empty bit vector of streets. Single + // tokens that are synonyms to streets are ignored. Moreover, + // each time a token that looks like a beginning of a house number + // is met, we try to use current intersection of tokens as a + // street layer and try to match BUILDINGs or POIs. + CBVPtr allFeatures(m_streets, false /* isOwner */); size_t curToken = startToken; // This variable is used for prevention of duplicate calls to // CreateStreetsLayerAndMatchLowerLayers() with the same // arguments. - size_t lastStopToken = curToken; + size_t lastToken = startToken; - for (; curToken < m_numTokens && !m_usedTokens[curToken]; ++curToken) - { - auto const & token = m_params.GetTokens(curToken).front(); - if (IsStreetSynonymPrefix(token)) - continue; + // When true, no bit vectors were intersected with allFeatures at + // all. + bool emptyIntersection = true; - bool const isPrefix = curToken >= m_params.m_tokens.size(); - if (house_numbers::LooksLikeHouseNumber(token, isPrefix)) + // When true, allFeatures is in the incomplete state and can't be + // used for creation of street layers. + bool incomplete = false; + + auto createStreetsLayerAndMatchLowerLayers = [&]() + { + if (!allFeatures.IsEmpty() && !emptyIntersection && !incomplete && lastToken != curToken) { - CreateStreetsLayerAndMatchLowerLayers(startToken, curToken, allFeatures); - lastStopToken = curToken; + CreateStreetsLayerAndMatchLowerLayers(startToken, curToken, *allFeatures); + lastToken = curToken; } + }; - unique_ptr<coding::CompressedBitVector> buffer; - if (startToken == curToken || coding::CompressedBitVector::IsEmpty(allFeatures)) - buffer = coding::CompressedBitVector::Intersect(*m_streets, *m_addressFeatures[curToken]); - else - buffer = coding::CompressedBitVector::Intersect(*allFeatures, *m_addressFeatures[curToken]); + StreetTokensFilter filter([&](strings::UniString const & /* token */, size_t tag) + { + auto buffer = coding::CompressedBitVector::Intersect( + *allFeatures, *m_addressFeatures[tag]); + if (tag < curToken) + { + // This is the case for delayed + // street synonym. Therefore, + // allFeatures is temporarily in the + // incomplete state. + allFeatures.Set(move(buffer)); + emptyIntersection = false; + + incomplete = true; + return; + } + ASSERT_EQUAL(tag, curToken, ()); + + // |allFeatures| will become empty + // after the intersection. Therefore + // we need to create streets layer + // right now. + if (coding::CompressedBitVector::IsEmpty(buffer)) + createStreetsLayerAndMatchLowerLayers(); + + allFeatures.Set(move(buffer)); + emptyIntersection = false; + incomplete = false; + }); + + for (; curToken < m_numTokens && !m_usedTokens[curToken] && !allFeatures.IsEmpty(); ++curToken) + { + auto const & token = m_params.GetTokens(curToken).front(); + bool const isPrefix = curToken >= m_params.m_tokens.size(); - if (coding::CompressedBitVector::IsEmpty(buffer)) - break; + if (house_numbers::LooksLikeHouseNumber(token, isPrefix)) + createStreetsLayerAndMatchLowerLayers(); - allFeatures.swap(buffer); + filter.Put(token, isPrefix, curToken); } - - if (curToken != lastStopToken) - CreateStreetsLayerAndMatchLowerLayers(startToken, curToken, allFeatures); + createStreetsLayerAndMatchLowerLayers(); } } void Geocoder::CreateStreetsLayerAndMatchLowerLayers( - size_t startToken, size_t endToken, unique_ptr<coding::CompressedBitVector> const & features) + size_t startToken, size_t endToken, coding::CompressedBitVector const & features) { ASSERT(m_layers.empty(), ()); - if (coding::CompressedBitVector::IsEmpty(features)) + if (coding::CompressedBitVector::IsEmpty(&features)) return; - CBVPtr filtered(features.get(), false /* isOwner */); - if (m_filter->NeedToFilter(*features)) - filtered.Set(m_filter->Filter(*features).release(), true /* isOwner */); + CBVPtr filtered(&features, false /* isOwner */); + if (m_filter->NeedToFilter(features)) + filtered.Set(m_filter->Filter(features).release(), true /* isOwner */); m_layers.emplace_back(); MY_SCOPE_GUARD(cleanupGuard, bind(&vector<FeaturesLayer>::pop_back, &m_layers)); @@ -1138,7 +1171,7 @@ void Geocoder::CreateStreetsLayerAndMatchLowerLayers( InitLayer(SearchModel::SEARCH_TYPE_STREET, startToken, endToken, layer); vector<uint32_t> sortedFeatures; - sortedFeatures.reserve(features->PopCount()); + sortedFeatures.reserve(features.PopCount()); filtered.ForEach(MakeBackInsertFunctor(sortedFeatures)); layer.m_sortedFeatures = &sortedFeatures; diff --git a/search/geocoder.hpp b/search/geocoder.hpp index 439784a742..db8e905b98 100644 --- a/search/geocoder.hpp +++ b/search/geocoder.hpp @@ -245,8 +245,8 @@ private: // then performs geocoding in street vicinities. void GreedilyMatchStreets(); - void CreateStreetsLayerAndMatchLowerLayers( - size_t startToken, size_t endToken, unique_ptr<coding::CompressedBitVector> const & features); + void CreateStreetsLayerAndMatchLowerLayers(size_t startToken, size_t endToken, + coding::CompressedBitVector const & features); // Tries to find all paths in a search tree, where each edge is // marked with some substring of the query tokens. These paths are diff --git a/search/search_integration_tests/processor_test.cpp b/search/search_integration_tests/processor_test.cpp index 61c3af5e9c..844a33fa1f 100644 --- a/search/search_integration_tests/processor_test.cpp +++ b/search/search_integration_tests/processor_test.cpp @@ -59,6 +59,8 @@ UNIT_CLASS_TEST(ProcessorTest, Smoke) TestCity losAlamosCity(m2::PointD(10, 10), "Los Alamos", "en", 100 /* rank */); TestCity mskCity(m2::PointD(0, 0), "Moscow", "en", 100 /* rank */); + TestCity torontoCity(m2::PointD(-10, -10), "Toronto", "en", 100 /* rank */); + TestVillage longPondVillage(m2::PointD(15, 15), "Long Pond Village", "en", 10 /* rank */); TestStreet feynmanStreet( vector<m2::PointD>{m2::PointD(9.999, 9.999), m2::PointD(10, 10), m2::PointD(10.001, 10.001)}, @@ -94,16 +96,23 @@ UNIT_CLASS_TEST(ProcessorTest, Smoke) TestPOI lantern1(m2::PointD(10.0005, 10.0005), "lantern 1", "en"); TestPOI lantern2(m2::PointD(10.0006, 10.0005), "lantern 2", "en"); + TestStreet stradaDrive(vector<m2::PointD>{m2::PointD(-10.001, -10.001), m2::PointD(-10, -10), + m2::PointD(-9.999, -9.999)}, + "Strada drive", "en"); + TestBuilding terranceHouse(m2::PointD(-10, -10), "", "155", stradaDrive, "en"); + BuildWorld([&](TestMwmBuilder & builder) { builder.Add(wonderlandCountry); builder.Add(losAlamosCity); builder.Add(mskCity); + builder.Add(torontoCity); }); auto wonderlandId = BuildCountry(countryName, [&](TestMwmBuilder & builder) { builder.Add(losAlamosCity); builder.Add(mskCity); + builder.Add(torontoCity); builder.Add(longPondVillage); builder.Add(feynmanStreet); @@ -125,6 +134,9 @@ UNIT_CLASS_TEST(ProcessorTest, Smoke) builder.Add(quantumCafe); builder.Add(lantern1); builder.Add(lantern2); + + builder.Add(stradaDrive); + builder.Add(terranceHouse); }); SetViewport(m2::RectD(m2::PointD(-1.0, -1.0), m2::PointD(1.0, 1.0))); @@ -190,6 +202,11 @@ UNIT_CLASS_TEST(ProcessorTest, Smoke) TRules rules = {ExactMatch(wonderlandId, bornHouse)}; TEST(ResultsMatch("long pond 1st april street 8", rules), ()); } + + { + TRules rules = {ExactMatch(wonderlandId, terranceHouse)}; + TEST(ResultsMatch("Toronto strada drive 155", rules), ()); + } } UNIT_CLASS_TEST(ProcessorTest, SearchInWorld) |