Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
44
libs/search/pysearch/CMakeLists.txt
Normal file
44
libs/search/pysearch/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
project(pysearch)
|
||||
|
||||
set(
|
||||
SRC
|
||||
bindings.cpp
|
||||
)
|
||||
|
||||
include_directories(${CMAKE_BINARY_DIR})
|
||||
|
||||
omim_add_library(${PROJECT_NAME} MODULE ${SRC})
|
||||
|
||||
omim_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
search_quality
|
||||
search_tests_support
|
||||
search
|
||||
storage
|
||||
editor
|
||||
indexer
|
||||
geometry
|
||||
ge0
|
||||
platform
|
||||
mwm_diff
|
||||
coding
|
||||
base
|
||||
bsdiff
|
||||
ICU::i18n
|
||||
cppjansson
|
||||
opening_hours
|
||||
protobuf
|
||||
pugixml
|
||||
succinct
|
||||
${Boost_LIBRARIES}
|
||||
ZLIB::ZLIB
|
||||
)
|
||||
|
||||
link_qt5_core(${PROJECT_NAME})
|
||||
link_qt5_network(${PROJECT_NAME})
|
||||
|
||||
if (PLATFORM_MAC)
|
||||
omim_link_libraries(${PROJECT_NAME} "-Wl,-undefined,dynamic_lookup")
|
||||
endif()
|
||||
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")
|
||||
46
libs/search/pysearch/README.txt
Normal file
46
libs/search/pysearch/README.txt
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
This document describes how to use this module.
|
||||
|
||||
1. How to build?
|
||||
|
||||
To build the module you need Python3.7 (or higher) and Boost Python. Also, you
|
||||
need Qt5.5 (or higher), but you need it in any case if you're
|
||||
planning to build the project. On MacOS, Python3.7 should be
|
||||
installed by default, to get Boost via Brew just type in the shell:
|
||||
|
||||
brew update
|
||||
brew install boost-python3
|
||||
|
||||
On Debian, type in the shell:
|
||||
|
||||
sudo apt-get install libboost-*
|
||||
|
||||
Note that on MacOS Boost is built by default with libc++, on Debian
|
||||
Boost is built by default with libstdc++. Therefore, you can use
|
||||
only macx-clang and linux-clang specs correspondingly. It's wrong
|
||||
to use linux-clang-libc++ because it's generally a bad idea to have
|
||||
two implementations of the C++ standard library in the same
|
||||
application.
|
||||
|
||||
Then, invoke cmake from the shell, for example:
|
||||
|
||||
cmake <path-to-omim-directory>\
|
||||
-DPYBINDINGS=ON\
|
||||
-DPYBINDINGS_VERSION=3.7\
|
||||
-DPYTHON_INCLUDE_DIRS=<path-to-dir-with-Python.h>\
|
||||
-DCMAKE_PREFIX_PATH=<path-to-qt5.5>
|
||||
|
||||
make -k -j8 pysearch
|
||||
|
||||
To set the python paths correctly, refer to https://cmake.org/cmake/help/v3.0/module/FindPythonLibs.html
|
||||
and
|
||||
|
||||
python-config --includes
|
||||
|
||||
2. How to use?
|
||||
|
||||
As pysearch is a custom Python module, all that you need
|
||||
is to customize PYTHONPATH environment variable before running your
|
||||
scripts. For example:
|
||||
|
||||
PYTHONPATH=path-to-the-directory-with-pysearch.so \
|
||||
./search/pysearch/run_search_engine.py
|
||||
251
libs/search/pysearch/bindings.cpp
Normal file
251
libs/search/pysearch/bindings.cpp
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
#include "search/engine.hpp"
|
||||
#include "search/search_quality/helpers.hpp"
|
||||
#include "search/search_tests_support/test_search_engine.hpp"
|
||||
#include "search/search_tests_support/test_search_request.hpp"
|
||||
#include "search/tracer.hpp"
|
||||
|
||||
#include "indexer/classificator_loader.hpp"
|
||||
#include "indexer/data_source.hpp"
|
||||
|
||||
#include "storage/storage_defines.hpp"
|
||||
|
||||
#include "platform/local_country_file.hpp"
|
||||
#include "platform/local_country_file_utils.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
|
||||
#include "geometry/point2d.hpp"
|
||||
#include "geometry/rect2d.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
#include "base/file_name_utils.hpp"
|
||||
|
||||
#include "pyhelpers/module_version.hpp"
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "defines.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Mercator
|
||||
{
|
||||
Mercator() = default;
|
||||
Mercator(double x, double y) : m_x(x), m_y(y) {}
|
||||
explicit Mercator(m2::PointD const & m) : m_x(m.x), m_y(m.y) {}
|
||||
|
||||
string ToString() const
|
||||
{
|
||||
ostringstream os;
|
||||
os << "x: " << m_x << ", y: " << m_y;
|
||||
return os.str();
|
||||
}
|
||||
|
||||
double m_x = 0.0;
|
||||
double m_y = 0.0;
|
||||
};
|
||||
|
||||
struct Viewport
|
||||
{
|
||||
Viewport() = default;
|
||||
Viewport(Mercator const & min, Mercator const & max) : m_min(min), m_max(max) {}
|
||||
|
||||
string ToString() const
|
||||
{
|
||||
ostringstream os;
|
||||
os << "[" << m_min.ToString() << ", " << m_max.ToString() << "]";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
Mercator m_min;
|
||||
Mercator m_max;
|
||||
};
|
||||
|
||||
struct Params
|
||||
{
|
||||
string ToString() const
|
||||
{
|
||||
ostringstream os;
|
||||
os << m_query << ", " << m_locale << ", " << m_position.ToString() << ", " << m_viewport.ToString();
|
||||
return os.str();
|
||||
}
|
||||
|
||||
string m_query;
|
||||
string m_locale;
|
||||
Mercator m_position;
|
||||
Viewport m_viewport;
|
||||
};
|
||||
|
||||
struct Result
|
||||
{
|
||||
Result() = default;
|
||||
|
||||
explicit Result(search::Result const & r)
|
||||
{
|
||||
m_name = r.GetString();
|
||||
m_address = r.GetAddress();
|
||||
m_hasCenter = r.HasPoint();
|
||||
if (m_hasCenter)
|
||||
m_center = Mercator(r.GetFeatureCenter());
|
||||
}
|
||||
|
||||
string ToString() const
|
||||
{
|
||||
ostringstream os;
|
||||
os << m_name << " [ " << m_address;
|
||||
if (m_hasCenter)
|
||||
os << ", " << m_center.ToString();
|
||||
os << " ]";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
string m_name;
|
||||
string m_address;
|
||||
bool m_hasCenter = false;
|
||||
Mercator m_center;
|
||||
};
|
||||
|
||||
struct TraceResult
|
||||
{
|
||||
string ToString() const
|
||||
{
|
||||
ostringstream os;
|
||||
os << "parse: [" << strings::JoinStrings(m_parse, ", ") << "], ";
|
||||
os << "is_category: " << boolalpha << m_isCategory;
|
||||
return os.str();
|
||||
}
|
||||
|
||||
vector<string> m_parse;
|
||||
bool m_isCategory = false;
|
||||
};
|
||||
|
||||
struct SearchEngineProxy
|
||||
{
|
||||
SearchEngineProxy()
|
||||
{
|
||||
search::search_quality::InitDataSource(m_dataSource, "" /* mwmListPath */);
|
||||
search::search_quality::InitStorageData(m_affiliations, m_countryNameSynonyms);
|
||||
m_engine =
|
||||
search::search_quality::InitSearchEngine(m_dataSource, m_affiliations, "en" /* locale */, 1 /* numThreads */);
|
||||
}
|
||||
|
||||
search::SearchParams MakeSearchParams(Params const & params) const
|
||||
{
|
||||
search::SearchParams sp;
|
||||
sp.m_query = params.m_query;
|
||||
sp.m_inputLocale = params.m_locale;
|
||||
sp.m_mode = search::Mode::Everywhere;
|
||||
sp.m_position = m2::PointD(params.m_position.m_x, params.m_position.m_y);
|
||||
sp.m_needAddress = true;
|
||||
|
||||
auto const & bottomLeft = params.m_viewport.m_min;
|
||||
auto const & topRight = params.m_viewport.m_max;
|
||||
sp.m_viewport = m2::RectD(bottomLeft.m_x, bottomLeft.m_y, topRight.m_x, topRight.m_y);
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
||||
boost::python::list Query(Params const & params) const
|
||||
{
|
||||
m_engine->SetLocale(params.m_locale);
|
||||
search::tests_support::TestSearchRequest request(*m_engine, MakeSearchParams(params));
|
||||
request.Run();
|
||||
|
||||
boost::python::list results;
|
||||
for (auto const & result : request.Results())
|
||||
results.append(Result(result));
|
||||
return results;
|
||||
}
|
||||
|
||||
boost::python::list Trace(Params const & params) const
|
||||
{
|
||||
m_engine->SetLocale(params.m_locale);
|
||||
|
||||
auto sp = MakeSearchParams(params);
|
||||
auto tracer = make_shared<search::Tracer>();
|
||||
sp.m_tracer = tracer;
|
||||
|
||||
search::tests_support::TestSearchRequest request(*m_engine, sp);
|
||||
request.Run();
|
||||
|
||||
boost::python::list trs;
|
||||
for (auto const & parse : tracer->GetUniqueParses())
|
||||
{
|
||||
TraceResult tr;
|
||||
for (size_t i = 0; i < parse.m_ranges.size(); ++i)
|
||||
{
|
||||
auto const & range = parse.m_ranges[i];
|
||||
if (!range.Empty())
|
||||
tr.m_parse.push_back(ToString(static_cast<search::Tracer::Parse::TokenType>(i)));
|
||||
}
|
||||
tr.m_isCategory = parse.m_category;
|
||||
trs.append(tr);
|
||||
}
|
||||
|
||||
return trs;
|
||||
}
|
||||
|
||||
storage::Affiliations m_affiliations;
|
||||
storage::CountryNameSynonyms m_countryNameSynonyms;
|
||||
FrozenDataSource m_dataSource;
|
||||
unique_ptr<search::tests_support::TestSearchEngine> m_engine;
|
||||
};
|
||||
|
||||
void Init(string const & dataPath, string const & mwmPath)
|
||||
{
|
||||
classificator::Load();
|
||||
search::search_quality::SetPlatformDirs(dataPath, mwmPath);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
BOOST_PYTHON_MODULE(pysearch)
|
||||
{
|
||||
using namespace boost::python;
|
||||
scope().attr("__version__") = PYBINDINGS_VERSION;
|
||||
|
||||
def("init", &Init);
|
||||
|
||||
class_<Mercator>("Mercator")
|
||||
.def(init<double, double>())
|
||||
.def_readwrite("x", &Mercator::m_x)
|
||||
.def_readwrite("y", &Mercator::m_y)
|
||||
.def("to_string", &Mercator::ToString);
|
||||
|
||||
class_<Viewport>("Viewport")
|
||||
.def(init<Mercator const &, Mercator const &>())
|
||||
.def_readwrite("min", &Viewport::m_min)
|
||||
.def_readwrite("max", &Viewport::m_max)
|
||||
.def("to_string", &Viewport::ToString);
|
||||
|
||||
class_<Params>("Params")
|
||||
.def_readwrite("query", &Params::m_query)
|
||||
.def_readwrite("locale", &Params::m_locale)
|
||||
.def_readwrite("position", &Params::m_position)
|
||||
.def_readwrite("viewport", &Params::m_viewport)
|
||||
.def("to_string", &Params::ToString);
|
||||
|
||||
class_<Result>("Result")
|
||||
.def_readwrite("name", &Result::m_name)
|
||||
.def_readwrite("address", &Result::m_address)
|
||||
.def_readwrite("has_center", &Result::m_hasCenter)
|
||||
.def_readwrite("center", &Result::m_center)
|
||||
.def("__repr__", &Result::ToString);
|
||||
|
||||
class_<TraceResult>("TraceResult")
|
||||
.def_readwrite("parse", &TraceResult::m_parse)
|
||||
.def_readwrite("is_category", &TraceResult::m_isCategory)
|
||||
.def("__repr__", &TraceResult::ToString);
|
||||
|
||||
class_<SearchEngineProxy, boost::noncopyable>("SearchEngine")
|
||||
.def("query", &SearchEngineProxy::Query)
|
||||
.def("trace", &SearchEngineProxy::Trace);
|
||||
}
|
||||
29
libs/search/pysearch/run_search_engine.py
Normal file
29
libs/search/pysearch/run_search_engine.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import print_function
|
||||
import argparse
|
||||
import os
|
||||
import pysearch as search
|
||||
|
||||
|
||||
DIR = os.path.dirname(__file__)
|
||||
RESOURCE_PATH = os.path.realpath(os.path.join(DIR, '..', '..', 'data'))
|
||||
MWM_PATH = os.path.realpath(os.path.join(DIR, '..', '..', 'data'))
|
||||
|
||||
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument('-r', metavar='RESOURCE_PATH', default=RESOURCE_PATH, help='Path to resources directory.')
|
||||
parser.add_argument('-m', metavar='MWM_PATH', default=MWM_PATH, help='Path to mwm files.')
|
||||
args = parser.parse_args()
|
||||
|
||||
search.init(args.r, args.m)
|
||||
engine = search.SearchEngine()
|
||||
|
||||
params = search.Params()
|
||||
params.query = 'кафе юность'
|
||||
params.locale = 'ru'
|
||||
params.position = search.Mercator(37.618705, 67.455669)
|
||||
params.viewport = search.Viewport(search.Mercator(37.1336, 67.1349),
|
||||
search.Mercator(38.0314, 67.7348))
|
||||
print(engine.query(params))
|
||||
print(engine.trace(params))
|
||||
79
libs/search/pysearch/run_search_server.py
Normal file
79
libs/search/pysearch/run_search_server.py
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import print_function
|
||||
from http.server import BaseHTTPRequestHandler,HTTPServer
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import pysearch
|
||||
import urllib.parse
|
||||
|
||||
DIR = os.path.dirname(__file__)
|
||||
RESOURCE_PATH = os.path.realpath(os.path.join(DIR, '..', '..', 'data'))
|
||||
MWM_PATH = os.path.realpath(os.path.join(DIR, '..', '..', 'data'))
|
||||
PORT=8080
|
||||
|
||||
|
||||
class HTTPHandler(BaseHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
result = urllib.parse.urlparse(self.path)
|
||||
query = urllib.parse.parse_qs(result.query)
|
||||
|
||||
def sparam(name):
|
||||
return query[name][-1]
|
||||
|
||||
def fparam(name):
|
||||
return float(sparam(name))
|
||||
|
||||
params = pysearch.Params()
|
||||
try:
|
||||
params.query = sparam('query')
|
||||
params.locale = sparam('locale')
|
||||
params.position = pysearch.Mercator(fparam('posx'), fparam('posy'))
|
||||
params.viewport = pysearch.Viewport(
|
||||
pysearch.Mercator(fparam('minx'), fparam('miny')),
|
||||
pysearch.Mercator(fparam('maxx'), fparam('maxy')))
|
||||
except KeyError:
|
||||
self.send_response(400)
|
||||
return
|
||||
|
||||
results = HTTPHandler.engine.query(params)
|
||||
|
||||
responses = [{'name': result.name,
|
||||
'address': result.address,
|
||||
'has_center': result.has_center,
|
||||
'center': {'x': result.center.x,
|
||||
'y': result.center.y
|
||||
}
|
||||
}
|
||||
for result in results]
|
||||
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", "application/json")
|
||||
self.end_headers()
|
||||
self.wfile.write(json.dumps(responses).encode())
|
||||
|
||||
|
||||
def main(args):
|
||||
pysearch.init(args.r, args.m)
|
||||
engine = pysearch.SearchEngine()
|
||||
HTTPHandler.engine = pysearch.SearchEngine()
|
||||
|
||||
print('Starting HTTP server on port', PORT)
|
||||
server = HTTPServer(('', args.p), HTTPHandler)
|
||||
server.serve_forever()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument('-r', metavar='RESOURCE_PATH', default=RESOURCE_PATH,
|
||||
help='Path to resources directory.')
|
||||
parser.add_argument('-m', metavar='MWM_PATH', default=MWM_PATH,
|
||||
help='Path to mwm files.')
|
||||
parser.add_argument('-p', metavar='PORT', default=PORT,
|
||||
help='Port for the server to listen')
|
||||
args = parser.parse_args()
|
||||
|
||||
main(args)
|
||||
13
libs/search/pysearch/setup.py
Normal file
13
libs/search/pysearch/setup.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import sys
|
||||
module_dir = os.path.abspath(os.path.dirname(__file__))
|
||||
sys.path.insert(0, os.path.join(module_dir, '..', '..'))
|
||||
|
||||
from pyhelpers.setup import setup_omim_pybinding
|
||||
|
||||
|
||||
NAME = "pysearch"
|
||||
|
||||
setup_omim_pybinding(name=NAME)
|
||||
Loading…
Add table
Add a link
Reference in a new issue