[search] Numerous fixes to Geocoder (search query v2).

This commit is contained in:
Yuri Gorshenin 2015-12-11 17:04:26 +03:00 committed by Sergey Yershov
parent aca026daca
commit 32f1aeae5d
13 changed files with 66 additions and 87 deletions

View file

@ -13,7 +13,6 @@ namespace search
{
namespace
{
double constexpr kLookupRadiusM = 500.0;
size_t constexpr kMaxStreetIndex = 16;
size_t constexpr kSimilarityThresholdPercent = 10;
@ -34,6 +33,9 @@ double CalculateMinDistance(FeatureType const & ft, m2::PointD const & pt)
}
} // namespace
// static
double const ReverseGeocoder::kLookupRadiusM = 500.0;
void ReverseGeocoder::GetNearbyStreets(FeatureType const & addrFt, vector<Street> & streets)
{
m2::PointD const & center = feature::GetCenter(addrFt);

View file

@ -18,6 +18,8 @@ class ReverseGeocoder
Index & m_index;
public:
static double const kLookupRadiusM;
ReverseGeocoder(Index & index) : m_index(index) {}
struct Street

View file

@ -65,6 +65,7 @@ UNIT_TEST(HouseNumbersMatcher_Smoke)
TEST(HouseNumbersMatch("1234abcdef", "1234 abcdef"), ());
TEST(HouseNumbersMatch("10/42 корпус 2", "10"), ());
TEST(!HouseNumbersMatch("39", "39 с 79"), ());
TEST(!HouseNumbersMatch("127а корпус 2", "127"), ());
TEST(!HouseNumbersMatch("6 корпус 2", "7"), ());
TEST(!HouseNumbersMatch("10/42 корпус 2", "42"), ());

View file

@ -4,6 +4,8 @@
#include "std/vector.hpp"
#include "base/macros.hpp"
namespace search
{
namespace v2
@ -14,6 +16,7 @@ namespace v2
struct FeaturesLayer
{
FeaturesLayer();
FeaturesLayer(FeaturesLayer && layer) = default;
void Clear();
@ -24,6 +27,8 @@ struct FeaturesLayer
size_t m_startToken;
size_t m_endToken;
SearchModel::SearchType m_type;
DISALLOW_COPY(FeaturesLayer);
};
string DebugPrint(FeaturesLayer const & layer);

View file

@ -1,6 +1,6 @@
#include "search/v2/features_layer_matcher.hpp"
#include "search/projection_on_street.hpp"
#include "search/reverse_geocoder.hpp"
#include "indexer/scales.hpp"
@ -16,8 +16,7 @@ FeaturesLayerMatcher::FeaturesLayerMatcher(Index & index, MwmSet::MwmId const &
, m_reverseGeocoder(index)
, m_houseToStreetTable(HouseToStreetTable::Load(value))
, m_featuresVector(featuresVector)
, m_loader(value, featuresVector, scales::GetUpperScale(),
ProjectionOnStreetCalculator::kDefaultMaxDistMeters)
, m_loader(value, featuresVector, scales::GetUpperScale(), ReverseGeocoder::kLookupRadiusM)
{
ASSERT(m_houseToStreetTable.get(), ("Can't load HouseToStreetTable"));
}

View file

@ -38,16 +38,17 @@ public:
FeaturesVector const & featuresVector);
template <typename TFn>
void Match(FeaturesLayer & child, FeaturesLayer & parent, TFn && fn)
void Match(FeaturesLayer const & child, vector<uint32_t> const & sortedParentFeatures,
SearchModel::SearchType parentType, TFn && fn)
{
if (child.m_type >= parent.m_type)
if (child.m_type >= parentType)
return;
if (parent.m_type == SearchModel::SEARCH_TYPE_STREET)
if (parentType == SearchModel::SEARCH_TYPE_STREET)
{
if (child.m_type == SearchModel::SEARCH_TYPE_POI)
MatchPOIsWithStreets(child, parent, forward<TFn>(fn));
MatchPOIsWithStreets(child, sortedParentFeatures, parentType, forward<TFn>(fn));
else if (child.m_type == SearchModel::SEARCH_TYPE_BUILDING)
MatchBuildingsWithStreets(child, parent, forward<TFn>(fn));
MatchBuildingsWithStreets(child, sortedParentFeatures, parentType, forward<TFn>(fn));
return;
}
@ -60,7 +61,7 @@ public:
}
vector<m2::RectD> parentRects;
for (uint32_t featureId : parent.m_sortedFeatures)
for (uint32_t featureId : sortedParentFeatures)
{
FeatureType feature;
m_featuresVector.GetByIndex(featureId, feature);
@ -69,29 +70,33 @@ public:
parentRects.push_back(MercatorBounds::RectByCenterXYAndSizeInMeters(center, radius));
}
for (size_t j = 0; j < parent.m_sortedFeatures.size(); ++j)
for (size_t j = 0; j < sortedParentFeatures.size(); ++j)
{
for (size_t i = 0; i < child.m_sortedFeatures.size(); ++i)
{
if (parentRects[j].IsPointInside(childCenters[i]))
fn(child.m_sortedFeatures[i], parent.m_sortedFeatures[j]);
fn(child.m_sortedFeatures[i], sortedParentFeatures[j]);
}
}
}
private:
template <typename TFn>
void MatchPOIsWithStreets(FeaturesLayer const & child, FeaturesLayer const & parent, TFn && fn)
void MatchPOIsWithStreets(FeaturesLayer const & child,
vector<uint32_t> const & sortedParentFeatures,
SearchModel::SearchType parentType, TFn && fn)
{
ASSERT_EQUAL(child.m_type, SearchModel::SEARCH_TYPE_POI, ());
ASSERT_EQUAL(parent.m_type, SearchModel::SEARCH_TYPE_STREET, ());
ASSERT_EQUAL(parentType, SearchModel::SEARCH_TYPE_STREET, ());
for (uint32_t streetId : parent.m_sortedFeatures)
for (uint32_t streetId : sortedParentFeatures)
m_loader.ForEachInVicinity(streetId, child.m_sortedFeatures, bind(fn, _1, streetId));
}
template <typename TFn>
void MatchBuildingsWithStreets(FeaturesLayer & child, FeaturesLayer const & parent, TFn && fn)
void MatchBuildingsWithStreets(FeaturesLayer const & child,
vector<uint32_t> const & sortedParentFeatures,
SearchModel::SearchType parentType, TFn && fn)
{
// child.m_sortedFeatures contains only buildings matched by name,
// not by house number. So, we need to add to
@ -101,7 +106,7 @@ private:
auto const & checker = ftypes::IsBuildingChecker::Instance();
ASSERT_EQUAL(child.m_type, SearchModel::SEARCH_TYPE_BUILDING, ());
ASSERT_EQUAL(parent.m_type, SearchModel::SEARCH_TYPE_STREET, ());
ASSERT_EQUAL(parentType, SearchModel::SEARCH_TYPE_STREET, ());
vector<string> queryTokens;
NormalizeHouseNumber(child.m_subQuery, queryTokens);
@ -115,26 +120,21 @@ private:
return HouseNumbersMatch(feature.GetHouseNumber(), queryTokens);
};
vector<uint32_t> houseIds;
auto addEdge = [&](uint32_t houseId, FeatureType & houseFeature, uint32_t streetId)
{
vector<ReverseGeocoder::Street> streets;
m_reverseGeocoder.GetNearbyStreets(houseFeature, streets);
uint32_t streetIndex = m_houseToStreetTable->Get(houseId);
if (streetIndex < streets.size() && streets[streetIndex].m_id.m_index == streetId)
if (streetIndex < streets.size() && streets[streetIndex].m_id.m_mwmId == m_mwmId &&
streets[streetIndex].m_id.m_index == streetId)
{
houseIds.push_back(houseId);
fn(houseId, streetId);
}
};
for (uint32_t streetId : parent.m_sortedFeatures)
for (uint32_t streetId : sortedParentFeatures)
m_loader.FilterFeaturesInVicinity(streetId, filter, bind(addEdge, _1, _2, streetId));
my::SortUnique(houseIds);
child.m_sortedFeatures.swap(houseIds);
}
MwmSet::MwmId m_mwmId;

View file

@ -9,37 +9,32 @@ namespace search
namespace v2
{
void FeaturesLayerPathFinder::BuildGraph(FeaturesLayerMatcher & matcher,
vector<FeaturesLayer *> const & layers)
vector<FeaturesLayer const *> const & layers,
vector<uint32_t> & reachable)
{
m_graph.clear();
if (layers.empty())
return;
FeaturesLayer child;
reachable = layers.back()->m_sortedFeatures;
vector<uint32_t> tmpBuffer;
// The order matters here, as we need to intersect BUILDINGs with
// STREETs first, and then POIs with BUILDINGs.
for (size_t i = layers.size() - 1; i != 0; --i)
{
auto & child = (*layers[i - 1]);
auto & parent = (*layers[i]);
auto addEdges = [&](uint32_t from, uint32_t to)
tmpBuffer.clear();
auto addEdge = [&](uint32_t childFeature, uint32_t /* parentFeature */)
{
m_graph[to].push_back(from);
tmpBuffer.push_back(childFeature);
};
matcher.Match(child, parent, addEdges);
}
}
void FeaturesLayerPathFinder::Dfs(uint32_t u)
{
m_visited.insert(u);
auto const adj = m_graph.find(u);
if (adj == m_graph.end())
return;
for (uint32_t v : adj->second)
{
if (m_visited.count(v) == 0)
Dfs(v);
matcher.Match(*layers[i - 1], reachable, layers[i]->m_type, addEdge);
my::SortUnique(tmpBuffer);
reachable.swap(tmpBuffer);
}
}
} // namespace v2

View file

@ -2,8 +2,6 @@
#include "search/v2/features_layer.hpp"
#include "std/unordered_map.hpp"
#include "std/unordered_set.hpp"
#include "std/vector.hpp"
class FeaturesVector;
@ -18,36 +16,23 @@ class FeaturesLayerMatcher;
class FeaturesLayerPathFinder
{
public:
using TAdjList = vector<uint32_t>;
using TLayerGraph = unordered_map<uint32_t, TAdjList>;
template <typename TFn>
void ForEachReachableVertex(FeaturesLayerMatcher & matcher,
vector<FeaturesLayer *> const & layers, TFn && fn)
vector<FeaturesLayer const *> const & layers, TFn && fn)
{
if (layers.empty())
return;
BuildGraph(matcher, layers);
vector<uint32_t> reachable;
BuildGraph(matcher, layers, reachable);
m_visited.clear();
for (uint32_t featureId : (*layers.back()).m_sortedFeatures)
Dfs(featureId);
for (uint32_t featureId : (*layers.front()).m_sortedFeatures)
{
if (m_visited.count(featureId) != 0)
fn(featureId);
}
for (uint32_t featureId : reachable)
fn(featureId);
}
private:
void BuildGraph(FeaturesLayerMatcher & matcher, vector<FeaturesLayer *> const & layers);
void Dfs(uint32_t u);
TLayerGraph m_graph;
unordered_set<uint32_t> m_visited;
void BuildGraph(FeaturesLayerMatcher & matcher, vector<FeaturesLayer const *> const & layers,
vector<uint32_t> & reachable);
};
} // namespace v2
} // namespace search

View file

@ -260,7 +260,7 @@ void Geocoder::FindPaths()
};
// Layers ordered by a search type.
vector<FeaturesLayer *> sortedLayers;
vector<FeaturesLayer const *> sortedLayers;
sortedLayers.reserve(m_layers.size());
for (auto & layer : m_layers)
sortedLayers.push_back(&layer);

View file

@ -202,7 +202,7 @@ bool HouseNumbersMatch(string const & houseNumber, vector<string> const & queryT
++i;
++j;
}
return true;
return j == queryTokens.size();
}
} // namespace v2
} // namespace search

View file

@ -11,14 +11,6 @@ namespace search
{
namespace v2
{
SearchModel::SearchModel()
{
m_poiCheckers.push_back(&IsPeakChecker::Instance());
m_poiCheckers.push_back(&IsATMChecker::Instance());
m_poiCheckers.push_back(&IsFuelStationChecker::Instance());
m_poiCheckers.push_back(&IsRailwayStationChecker::Instance());
}
// static
SearchModel const & SearchModel::Instance()
{
@ -32,12 +24,6 @@ SearchModel::SearchType SearchModel::GetSearchType(FeatureType const & feature)
static auto const & streetChecker = IsStreetChecker::Instance();
static auto const & localityChecker = IsLocalityChecker::Instance();
for (auto const * checker : m_poiCheckers)
{
if ((*checker)(feature))
return SEARCH_TYPE_POI;
}
if (buildingChecker(feature))
return SEARCH_TYPE_BUILDING;
@ -64,7 +50,7 @@ SearchModel::SearchType SearchModel::GetSearchType(FeatureType const & feature)
}
}
return SEARCH_TYPE_COUNT;
return SEARCH_TYPE_POI;
}
string DebugPrint(SearchModel::SearchType type)

View file

@ -3,6 +3,8 @@
#include "std/string.hpp"
#include "std/vector.hpp"
#include "base/macros.hpp"
class FeatureType;
namespace ftypes
@ -31,14 +33,14 @@ public:
SEARCH_TYPE_COUNT
};
SearchModel();
static SearchModel const & Instance();
SearchType GetSearchType(FeatureType const & feature) const;
private:
vector<ftypes::BaseChecker const *> m_poiCheckers;
SearchModel() = default;
DISALLOW_COPY_AND_MOVE(SearchModel);
};
string DebugPrint(SearchModel::SearchType type);

View file

@ -50,8 +50,10 @@ void StreetVicinityLoader::LoadStreet(uint32_t featureId, Street & street)
covering::CoveringGetter coveringGetter(street.m_rect, covering::ViewportWithLowLevels);
auto const & intervals = coveringGetter.Get(m_scale);
for (auto const & interval : intervals)
{
m_index.ForEachInIntervalAndScale(MakeBackInsertFunctor(street.m_features), interval.first,
interval.second, m_scale);
}
if (!points.empty())
street.m_calculator = make_unique<ProjectionOnStreetCalculator>(move(points), m_offsetMeters);