Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
374
libs/search/geocoder.hpp
Normal file
374
libs/search/geocoder.hpp
Normal file
|
|
@ -0,0 +1,374 @@
|
|||
#pragma once
|
||||
|
||||
#include "search/cancel_exception.hpp"
|
||||
#include "search/categories_cache.hpp"
|
||||
#include "search/cbv.hpp"
|
||||
#include "search/cities_boundaries_table.hpp"
|
||||
#include "search/cuisine_filter.hpp"
|
||||
#include "search/feature_offset_match.hpp"
|
||||
#include "search/features_layer.hpp"
|
||||
#include "search/features_layer_path_finder.hpp"
|
||||
#include "search/filtering_params.hpp"
|
||||
#include "search/geocoder_context.hpp"
|
||||
#include "search/geocoder_locality.hpp"
|
||||
#include "search/geometry_cache.hpp"
|
||||
#include "search/mode.hpp"
|
||||
#include "search/model.hpp"
|
||||
#include "search/mwm_context.hpp"
|
||||
#include "search/postcode_points.hpp"
|
||||
#include "search/query_params.hpp"
|
||||
#include "search/streets_matcher.hpp"
|
||||
#include "search/token_range.hpp"
|
||||
#include "search/tracer.hpp"
|
||||
|
||||
#include "indexer/mwm_set.hpp"
|
||||
|
||||
#include "geometry/point2d.hpp"
|
||||
#include "geometry/rect2d.hpp"
|
||||
|
||||
#include "base/cancellable.hpp"
|
||||
#include "base/dfa_helpers.hpp"
|
||||
#include "base/levenshtein_dfa.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
class CategoriesHolder;
|
||||
class DataSource;
|
||||
class MwmValue;
|
||||
|
||||
namespace storage
|
||||
{
|
||||
class CountryInfoGetter;
|
||||
} // namespace storage
|
||||
|
||||
namespace search
|
||||
{
|
||||
class FeaturesFilter;
|
||||
class FeaturesLayerMatcher;
|
||||
class PreRanker;
|
||||
class TokenSlice;
|
||||
|
||||
// This class is used to retrieve all features corresponding to a
|
||||
// search query. Search query is represented as a sequence of tokens
|
||||
// (including synonyms for these tokens), and Geocoder tries to build
|
||||
// all possible partitions (or layers) of the search query, where each
|
||||
// layer is a set of features corresponding to some search class
|
||||
// (e.g. POI, BUILDING, STREET, etc., see search_model.hpp).
|
||||
// Then, Geocoder builds a layered graph, with edges between features
|
||||
// on adjacent layers (e.g. between BUILDING ans STREET, STREET and
|
||||
// CITY, etc.). Usually an edge between two features means that a
|
||||
// feature from the lowest layer geometrically belongs to a feature
|
||||
// from the highest layer (BUILDING is located on STREET, STREET is
|
||||
// located inside CITY, CITY is located inside STATE, etc.). Final
|
||||
// part is to find all paths through this layered graph and report all
|
||||
// features from the lowest layer, that are reachable from the
|
||||
// highest layer.
|
||||
class Geocoder
|
||||
{
|
||||
public:
|
||||
struct Params : public QueryParams
|
||||
{
|
||||
Mode m_mode = Mode::Everywhere;
|
||||
m2::RectD m_pivot;
|
||||
std::optional<m2::PointD> m_position;
|
||||
Locales m_categoryLocales;
|
||||
std::vector<uint32_t> m_cuisineTypes;
|
||||
std::vector<uint32_t> m_preferredTypes;
|
||||
std::shared_ptr<Tracer> m_tracer;
|
||||
|
||||
RecommendedFilteringParams m_filteringParams;
|
||||
|
||||
int m_scale = scales::GetUpperScale();
|
||||
|
||||
bool m_useDebugInfo = false; // Set to true for debug logs and tests.
|
||||
};
|
||||
|
||||
struct LocalitiesCaches
|
||||
{
|
||||
LocalitiesCaches(base::Cancellable const & cancellable);
|
||||
void Clear();
|
||||
|
||||
CountriesCache m_countries;
|
||||
StatesCache m_states;
|
||||
CitiesTownsOrVillagesCache m_citiesTownsOrVillages;
|
||||
VillagesCache m_villages;
|
||||
};
|
||||
|
||||
Geocoder(DataSource const & dataSource, storage::CountryInfoGetter const & infoGetter,
|
||||
CategoriesHolder const & categories, CitiesBoundariesTable const & citiesBoundaries, PreRanker & preRanker,
|
||||
LocalitiesCaches & localitiesCaches, base::Cancellable const & cancellable);
|
||||
~Geocoder();
|
||||
|
||||
// Sets search query params.
|
||||
void SetParams(Params const & params);
|
||||
|
||||
// Starts geocoding, retrieved features will be appended to
|
||||
// |results|.
|
||||
void GoEverywhere();
|
||||
void GoInViewport();
|
||||
|
||||
// Ends geocoding and informs the following stages
|
||||
// of the pipeline (PreRanker and further).
|
||||
// This method must be called from the previous stage
|
||||
// of the pipeline (the Processor).
|
||||
// If |cancelled| is true, the reason for calling Finish must
|
||||
// be the cancellation of processing the search request, otherwise
|
||||
// the reason must be the normal exit from GoEverywhere or GoInViewport.
|
||||
//
|
||||
// *NOTE* The caller assumes that a call to this method will never
|
||||
// result in search::CancelException even if the shutdown takes
|
||||
// noticeable time.
|
||||
void Finish(bool cancelled);
|
||||
|
||||
void CacheWorldLocalities();
|
||||
void ClearCaches();
|
||||
|
||||
private:
|
||||
enum class RectId
|
||||
{
|
||||
Pivot,
|
||||
Locality,
|
||||
Postcode,
|
||||
Suburb,
|
||||
Count
|
||||
};
|
||||
|
||||
using MwmInfoPtr = std::shared_ptr<MwmInfo>;
|
||||
struct ExtendedMwmInfos
|
||||
{
|
||||
struct ExtendedMwmInfo
|
||||
{
|
||||
bool operator<(ExtendedMwmInfo const & rhs) const { return m_score < rhs.m_score; }
|
||||
|
||||
MwmInfoPtr m_info;
|
||||
MwmContext::MwmType m_type;
|
||||
|
||||
// Score is a rect distance, with exceptions for World, viewport and users's position.
|
||||
// Less score is better for search priority.
|
||||
double m_score;
|
||||
};
|
||||
|
||||
std::vector<ExtendedMwmInfo> m_infos;
|
||||
size_t m_firstBatchSize = 0;
|
||||
};
|
||||
|
||||
struct Postcodes
|
||||
{
|
||||
void Clear()
|
||||
{
|
||||
m_tokenRange.Clear();
|
||||
m_countryFeatures.Reset();
|
||||
m_worldFeatures.Reset();
|
||||
}
|
||||
|
||||
bool Has(uint32_t id, bool searchWorld = false) const
|
||||
{
|
||||
if (searchWorld)
|
||||
return m_worldFeatures.HasBit(id);
|
||||
return m_countryFeatures.HasBit(id);
|
||||
}
|
||||
|
||||
bool IsEmpty() const { return m_countryFeatures.IsEmpty() && m_worldFeatures.IsEmpty(); }
|
||||
|
||||
TokenRange m_tokenRange;
|
||||
CBV m_countryFeatures;
|
||||
CBV m_worldFeatures;
|
||||
};
|
||||
|
||||
// Sets search query params for categorial search.
|
||||
void SetParamsForCategorialSearch(Params const & params);
|
||||
|
||||
void GoImpl(std::vector<MwmInfoPtr> const & infos, bool inViewport);
|
||||
|
||||
template <typename Locality>
|
||||
using TokenToLocalities = std::map<TokenRange, std::vector<Locality>>;
|
||||
|
||||
QueryParams::Token const & GetTokens(size_t i) const;
|
||||
|
||||
// Creates a cache of posting lists corresponding to features in m_context
|
||||
// for each token and saves it to m_addressFeatures.
|
||||
void InitBaseContext(BaseContext & ctx);
|
||||
|
||||
void InitLayer(Model::Type type, TokenRange const & tokenRange, FeaturesLayer & layer);
|
||||
|
||||
void FillLocalityCandidates(BaseContext const & ctx, CBV const & filter, size_t const maxNumLocalities,
|
||||
std::vector<Locality> & preLocalities);
|
||||
|
||||
void FillLocalitiesTable(BaseContext const & ctx);
|
||||
|
||||
void FillVillageLocalities(BaseContext const & ctx);
|
||||
|
||||
bool CityHasPostcode(BaseContext const & ctx) const;
|
||||
|
||||
template <typename Fn>
|
||||
void ForEachCountry(ExtendedMwmInfos const & infos, Fn && fn);
|
||||
|
||||
// Throws CancelException if cancelled.
|
||||
void BailIfCancelled() { ::search::BailIfCancelled(m_cancellable); }
|
||||
|
||||
// A fast-path branch for categorial requests.
|
||||
void MatchCategories(BaseContext & ctx, bool aroundPivot);
|
||||
|
||||
// Tries to find all countries and states in a search query and then
|
||||
// performs matching of cities in found maps.
|
||||
void MatchRegions(BaseContext & ctx, Region::Type type);
|
||||
|
||||
// Tries to find all cities in a search query and then performs
|
||||
// matching of streets in found cities.
|
||||
void MatchCities(BaseContext & ctx);
|
||||
|
||||
// Tries to do geocoding without localities, ie. find POIs,
|
||||
// BUILDINGs and STREETs without knowledge about country, state,
|
||||
// city or village. If during the geocoding too many features are
|
||||
// retrieved, viewport is used to throw away excess features.
|
||||
void MatchAroundPivot(BaseContext & ctx);
|
||||
|
||||
class CentersFilter
|
||||
{
|
||||
buffer_vector<m2::PointD, 4> m_centers;
|
||||
|
||||
public:
|
||||
void Add(m2::PointD const & pt) { m_centers.push_back(pt); }
|
||||
|
||||
template <class FnT>
|
||||
void ClusterizeStreets(std::vector<uint32_t> & streets, Geocoder const & geocoder, FnT && fn) const;
|
||||
};
|
||||
|
||||
// Tries to do geocoding in a limited scope, assuming that knowledge
|
||||
// about high-level features, like cities or countries, is
|
||||
// incorporated into |filter|.
|
||||
void LimitedSearch(BaseContext & ctx, FeaturesFilter const & filter, CentersFilter const & centers);
|
||||
|
||||
template <typename Fn>
|
||||
void WithPostcodes(BaseContext & ctx, Fn && fn);
|
||||
|
||||
// Tries to match some adjacent tokens in the query as streets and
|
||||
// then performs geocoding in street vicinities.
|
||||
void GreedilyMatchStreets(BaseContext & ctx, CentersFilter const & centers);
|
||||
// Matches suburbs and streets inside suburbs like |GreedilyMatchStreets|.
|
||||
void GreedilyMatchStreetsWithSuburbs(BaseContext & ctx, CentersFilter const & centers);
|
||||
|
||||
void CreateStreetsLayerAndMatchLowerLayers(BaseContext & ctx, StreetsMatcher::Prediction const & prediction,
|
||||
CentersFilter const & centers, bool makeRelaxed);
|
||||
|
||||
void ProcessStreets(BaseContext & ctx, CentersFilter const & centers, CBV const & streets);
|
||||
|
||||
// Tries to find all paths in a search tree, where each edge is
|
||||
// marked with some substring of the query tokens. These paths are
|
||||
// called "layer sequence" and current path is stored in |m_layers|.
|
||||
void MatchPOIsAndBuildings(BaseContext & ctx, size_t curToken, CBV const & filter);
|
||||
|
||||
// Returns true if current path in the search tree (see comment for
|
||||
// MatchPOIsAndBuildings()) looks sane. This method is used as a fast
|
||||
// pre-check to cut off unnecessary work.
|
||||
bool IsLayerSequenceSane(std::vector<FeaturesLayer> const & layers) const;
|
||||
|
||||
/// @returns kInvalidFeatureId in no matching found.
|
||||
uint32_t MatchWorld2Country(FeatureID const & id) const;
|
||||
// Finds all paths through layers and emits reachable features from the lowest layer.
|
||||
void FindPaths(BaseContext & ctx);
|
||||
|
||||
void TraceResult(Tracer & tracer, BaseContext const & ctx, MwmSet::MwmId const & mwmId, uint32_t ftId,
|
||||
Model::Type type, TokenRange const & tokenRange);
|
||||
|
||||
// Forms result and feeds it to |m_preRanker|.
|
||||
void EmitResult(BaseContext & ctx, FeatureID const & id, Model::Type type, TokenRange const & tokenRange,
|
||||
IntersectionResult const * geoParts, bool allTokensUsed, bool exactMatch);
|
||||
void EmitResult(BaseContext & ctx, Region const & region, TokenRange const & tokenRange, bool allTokensUsed,
|
||||
bool exactMatch);
|
||||
void EmitResult(BaseContext & ctx, City const & city, TokenRange const & tokenRange, bool allTokensUsed);
|
||||
|
||||
// Tries to match unclassified objects from lower layers, like
|
||||
// parks, forests, lakes, rivers, etc. This method finds all
|
||||
// UNCLASSIFIED objects that match to all currently unused tokens.
|
||||
void MatchUnclassified(BaseContext & ctx, size_t curToken);
|
||||
|
||||
// A wrapper around RetrievePostcodeFeatures.
|
||||
CBV RetrievePostcodeFeatures(MwmContext const & context, TokenSlice const & slice);
|
||||
|
||||
// A caching wrapper around Retrieval::RetrieveGeometryFeatures.
|
||||
CBV RetrieveGeometryFeatures(MwmContext const & context, m2::RectD const & rect, RectId id);
|
||||
|
||||
// This is a faster wrapper around SearchModel::GetSearchType(), as
|
||||
// it uses pre-loaded lists of streets and villages.
|
||||
[[nodiscard]] bool GetTypeInGeocoding(BaseContext const & ctx, uint32_t featureId, Model::Type & type);
|
||||
|
||||
// Reorders maps in a way that prefix consists of "best" maps to search and suffix consists of all
|
||||
// other maps ordered by minimum distance from pivot. Returns ExtendedMwmInfos structure which
|
||||
// consists of vector of mwms with MwmType information and number of "best" maps to search.
|
||||
// For viewport mode prefix consists of maps intersecting with pivot ordered by distance from
|
||||
// pivot center.
|
||||
// For non-viewport search mode prefix consists of maps intersecting with pivot, map with user
|
||||
// location and maps with cities matched to the query, sorting prefers mwms that contain the
|
||||
// user's position.
|
||||
ExtendedMwmInfos OrderCountries(bool inViewport, std::vector<MwmInfoPtr> const & infos);
|
||||
|
||||
DataSource const & m_dataSource;
|
||||
storage::CountryInfoGetter const & m_infoGetter;
|
||||
CategoriesHolder const & m_categories;
|
||||
|
||||
StreetsCache m_streetsCache;
|
||||
SuburbsCache m_suburbsCache;
|
||||
LocalitiesCaches & m_localitiesCaches;
|
||||
HotelsCache m_hotelsCache;
|
||||
FoodCache m_foodCache;
|
||||
cuisine_filter::CuisineFilter m_cuisineFilter;
|
||||
|
||||
base::Cancellable const & m_cancellable;
|
||||
|
||||
// Geocoder params.
|
||||
Params m_params;
|
||||
|
||||
// This field is used to map features to a limited number of search
|
||||
// classes.
|
||||
Model m_model;
|
||||
|
||||
// Following fields are set up by Search() method and can be
|
||||
// modified and used only from Search() or its callees.
|
||||
|
||||
MwmSet::MwmId m_worldId;
|
||||
|
||||
// Context of the currently processed mwm.
|
||||
std::unique_ptr<MwmContext> m_context;
|
||||
|
||||
// m_cities stores both big cities that are visible at World.mwm
|
||||
// and small villages and hamlets that are not.
|
||||
TokenToLocalities<City> m_cities;
|
||||
TokenToLocalities<Region> m_regions[Region::TYPE_COUNT];
|
||||
CitiesBoundariesTable const & m_citiesBoundaries;
|
||||
|
||||
// Caches of features in rects. These caches are separated from
|
||||
// TokenToLocalities because the latter are quite lightweight and not
|
||||
// all of them are needed.
|
||||
PivotRectsCache m_pivotRectsCache;
|
||||
PivotRectsCache m_postcodesRectsCache;
|
||||
PivotRectsCache m_suburbsRectsCache;
|
||||
LocalityRectsCache m_localityRectsCache;
|
||||
|
||||
PostcodePointsCache m_postcodePointsCache;
|
||||
|
||||
// Postcodes features in the mwm that is currently being processed and World.mwm.
|
||||
Postcodes m_postcodes;
|
||||
|
||||
// This filter is used to throw away excess features.
|
||||
FeaturesFilter const * m_filter;
|
||||
|
||||
// Features matcher for layers intersection.
|
||||
std::map<MwmSet::MwmId, std::unique_ptr<FeaturesLayerMatcher>> m_matchersCache;
|
||||
FeaturesLayerMatcher * m_matcher;
|
||||
|
||||
// Path finder for interpretations.
|
||||
FeaturesLayerPathFinder m_finder;
|
||||
|
||||
// Search query params prepared for retrieval.
|
||||
std::vector<SearchTrieRequest<strings::LevenshteinDFA>> m_tokenRequests;
|
||||
SearchTrieRequest<strings::PrefixDFAModifier<strings::LevenshteinDFA>> m_prefixTokenRequest;
|
||||
|
||||
ResultTracer m_resultTracer;
|
||||
|
||||
PreRanker & m_preRanker;
|
||||
};
|
||||
} // namespace search
|
||||
Loading…
Add table
Add a link
Reference in a new issue