mirror of https://github.com/kiwix/libkiwix.git
Introduce SearchInfo.
SearchInfo is a small helper structure to store information about the queried search. It regroup already existing information (`patternString`, geo query, ...) in one structure. It is also used as key in the cache instead of using a generated string.
This commit is contained in:
parent
e7293346be
commit
d740ffe465
|
@ -109,6 +109,55 @@ unsigned int getCacheLength(const char* name, unsigned int defaultVal) {
|
||||||
}
|
}
|
||||||
} // unnamed namespace
|
} // unnamed namespace
|
||||||
|
|
||||||
|
SearchInfo::SearchInfo(const std::string& pattern)
|
||||||
|
: pattern(pattern),
|
||||||
|
geoQuery()
|
||||||
|
{}
|
||||||
|
|
||||||
|
SearchInfo::SearchInfo(const std::string& pattern, GeoQuery geoQuery)
|
||||||
|
: pattern(pattern),
|
||||||
|
geoQuery(geoQuery)
|
||||||
|
{}
|
||||||
|
|
||||||
|
SearchInfo::SearchInfo(const RequestContext& request)
|
||||||
|
: pattern(request.get_optional_param<std::string>("pattern", "")),
|
||||||
|
geoQuery(),
|
||||||
|
bookName(request.get_optional_param<std::string>("content", ""))
|
||||||
|
{
|
||||||
|
/* Retrive geo search */
|
||||||
|
try {
|
||||||
|
auto latitude = request.get_argument<float>("latitude");
|
||||||
|
auto longitude = request.get_argument<float>("longitude");
|
||||||
|
auto distance = request.get_argument<float>("distance");
|
||||||
|
geoQuery = GeoQuery(latitude, longitude, distance);
|
||||||
|
} catch(const std::out_of_range&) {}
|
||||||
|
catch(const std::invalid_argument&) {}
|
||||||
|
|
||||||
|
if (!geoQuery && pattern.empty()) {
|
||||||
|
throw std::invalid_argument("No query provided.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zim::Query SearchInfo::getZimQuery(bool verbose) const {
|
||||||
|
zim::Query query;
|
||||||
|
if(pattern.empty()) {
|
||||||
|
// Execute geo-search
|
||||||
|
if (verbose) {
|
||||||
|
cout << "Performing geo query `" << geoQuery.distance << "&(" << geoQuery.latitude << ";" << geQuery.longitude << ")'" << endl;
|
||||||
|
}
|
||||||
|
query.setQuery("");
|
||||||
|
query.setGeorange(geoQuery.latitude, geoQuery.longitude, geoQuery.distance);
|
||||||
|
} else {
|
||||||
|
// Execute Ft search
|
||||||
|
if (verbose) {
|
||||||
|
cout << "Performing query `" << pattern << "'" << endl;
|
||||||
|
}
|
||||||
|
query.setQuery(pattern);
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static IdNameMapper defaultNameMapper;
|
static IdNameMapper defaultNameMapper;
|
||||||
|
|
||||||
static MHD_Result staticHandlerCallback(void* cls,
|
static MHD_Result staticHandlerCallback(void* cls,
|
||||||
|
@ -499,48 +548,26 @@ std::unique_ptr<Response> InternalServer::handle_search(const RequestContext& re
|
||||||
printf("** running handle_search\n");
|
printf("** running handle_search\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string patternString;
|
|
||||||
try {
|
try {
|
||||||
patternString = request.get_argument("pattern");
|
auto searchInfo = SearchInfo(request);
|
||||||
} catch (const std::out_of_range&) {}
|
|
||||||
|
|
||||||
/* Retrive geo search */
|
std::string bookId;
|
||||||
bool has_geo_query = false;
|
|
||||||
float latitude = 0;
|
|
||||||
float longitude = 0;
|
|
||||||
float distance = 0;
|
|
||||||
try {
|
|
||||||
latitude = request.get_argument<float>("latitude");
|
|
||||||
longitude = request.get_argument<float>("longitude");
|
|
||||||
distance = request.get_argument<float>("distance");
|
|
||||||
has_geo_query = true;
|
|
||||||
} catch(const std::out_of_range&) {}
|
|
||||||
catch(const std::invalid_argument&) {}
|
|
||||||
|
|
||||||
std::string bookName, bookId;
|
|
||||||
std::shared_ptr<zim::Archive> archive;
|
std::shared_ptr<zim::Archive> archive;
|
||||||
|
if (!searchInfo.bookName.empty()) {
|
||||||
try {
|
try {
|
||||||
bookName = request.get_argument("content");
|
bookId = mp_nameMapper->getIdForName(searchInfo.bookName);
|
||||||
bookId = mp_nameMapper->getIdForName(bookName);
|
|
||||||
archive = mp_library->getArchiveById(bookId);
|
archive = mp_library->getArchiveById(bookId);
|
||||||
} catch (const std::out_of_range&) {}
|
} catch (const std::out_of_range&) {
|
||||||
|
|
||||||
/* Make the search */
|
|
||||||
if (patternString.empty() && ! has_geo_query) {
|
|
||||||
return HTTP400HtmlResponse(*this, request)
|
|
||||||
+ invalidUrlMsg
|
|
||||||
+ std::string("No query provided.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!archive && !bookName.empty()) {
|
|
||||||
auto data = get_default_data();
|
auto data = get_default_data();
|
||||||
data.set("pattern", encodeDiples(patternString));
|
data.set("pattern", encodeDiples(searchInfo.pattern));
|
||||||
data.set("root", m_root);
|
data.set("root", m_root);
|
||||||
auto response = ContentResponse::build(*this, RESOURCE::templates::no_search_result_html, data, "text/html; charset=utf-8");
|
auto response = ContentResponse::build(*this, RESOURCE::templates::no_search_result_html, data, "text/html; charset=utf-8");
|
||||||
response->set_code(MHD_HTTP_NOT_FOUND);
|
response->set_code(MHD_HTTP_NOT_FOUND);
|
||||||
return withTaskbarInfo(bookName, archive.get(), std::move(response));
|
return withTaskbarInfo(searchInfo.bookName, archive.get(), std::move(response));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make the search */
|
||||||
std::shared_ptr<zim::Searcher> searcher;
|
std::shared_ptr<zim::Searcher> searcher;
|
||||||
if (archive) {
|
if (archive) {
|
||||||
searcher = searcherCache.getOrPut(bookId, [=](){ return std::make_shared<zim::Searcher>(*archive);});
|
searcher = searcherCache.getOrPut(bookId, [=](){ return std::make_shared<zim::Searcher>(*archive);});
|
||||||
|
@ -574,41 +601,22 @@ std::unique_ptr<Response> InternalServer::handle_search(const RequestContext& re
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the results */
|
/* Get the results */
|
||||||
std::string queryString;
|
|
||||||
try {
|
|
||||||
zim::Query query;
|
|
||||||
if (patternString.empty()) {
|
|
||||||
// Execute geo-search
|
|
||||||
if (m_verbose.load()) {
|
|
||||||
cout << "Performing geo query `" << distance << "&(" << latitude << ";" << longitude << ")'" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
query.setQuery("");
|
|
||||||
queryString = "GEO:" + to_string(latitude) + to_string(longitude) + to_string(distance);
|
|
||||||
query.setGeorange(latitude, longitude, distance);
|
|
||||||
} else {
|
|
||||||
// Execute Ft search
|
|
||||||
if (m_verbose.load()) {
|
|
||||||
cout << "Performing query `" << patternString << "'" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
queryString = "FT:" + removeAccents(patternString);
|
|
||||||
query.setQuery(queryString);
|
|
||||||
}
|
|
||||||
queryString = bookId + queryString;
|
|
||||||
|
|
||||||
std::shared_ptr<zim::Search> search;
|
std::shared_ptr<zim::Search> search;
|
||||||
search = searchCache.getOrPut(queryString, [=](){ return make_shared<zim::Search>(searcher->search(query));});
|
search = searchCache.getOrPut(searchInfo, [=](){ return make_shared<zim::Search>(searcher->search(searchInfo.getZimQuery(m_verbose.load())));});
|
||||||
|
|
||||||
SearchRenderer renderer(search->getResults(start, pageLength), mp_nameMapper, mp_library, start,
|
SearchRenderer renderer(search->getResults(start, pageLength), mp_nameMapper, mp_library, start,
|
||||||
search->getEstimatedMatches());
|
search->getEstimatedMatches());
|
||||||
renderer.setSearchPattern(patternString);
|
renderer.setSearchPattern(searchInfo.pattern);
|
||||||
renderer.setSearchContent(bookName);
|
renderer.setSearchContent(searchInfo.bookName);
|
||||||
renderer.setProtocolPrefix(m_root + "/");
|
renderer.setProtocolPrefix(m_root + "/");
|
||||||
renderer.setSearchProtocolPrefix(m_root + "/search?");
|
renderer.setSearchProtocolPrefix(m_root + "/search?");
|
||||||
renderer.setPageLength(pageLength);
|
renderer.setPageLength(pageLength);
|
||||||
auto response = ContentResponse::build(*this, renderer.getHtml(), "text/html; charset=utf-8");
|
auto response = ContentResponse::build(*this, renderer.getHtml(), "text/html; charset=utf-8");
|
||||||
return withTaskbarInfo(bookName, archive.get(), std::move(response));
|
return withTaskbarInfo(searchInfo.bookName, archive.get(), std::move(response));
|
||||||
|
} catch (const std::invalid_argument& e) {
|
||||||
|
return HTTP400HtmlResponse(*this, request)
|
||||||
|
+ invalidUrlMsg
|
||||||
|
+ std::string(e.what());
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
std::cerr << e.what() << std::endl;
|
std::cerr << e.what() << std::endl;
|
||||||
return Response::build_500(*this, e.what());
|
return Response::build_500(*this, e.what());
|
||||||
|
|
|
@ -43,9 +43,53 @@ extern "C" {
|
||||||
|
|
||||||
namespace kiwix {
|
namespace kiwix {
|
||||||
|
|
||||||
|
struct GeoQuery {
|
||||||
|
GeoQuery()
|
||||||
|
: GeoQuery(0, 0, -1)
|
||||||
|
{}
|
||||||
|
|
||||||
|
GeoQuery(float latitude, float longitude, float distance)
|
||||||
|
: latitude(latitude), longitude(longitude), distance(distance)
|
||||||
|
{}
|
||||||
|
float latitude;
|
||||||
|
float longitude;
|
||||||
|
float distance;
|
||||||
|
|
||||||
|
explicit operator bool() const {
|
||||||
|
return distance >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator<(const GeoQuery& l, const GeoQuery& r)
|
||||||
|
{
|
||||||
|
return std::tie(l.latitude, l.longitude, l.distance)
|
||||||
|
< std::tie(r.latitude, r.longitude, r.distance); // keep the same order
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SearchInfo {
|
||||||
|
public:
|
||||||
|
SearchInfo(const std::string& pattern);
|
||||||
|
SearchInfo(const std::string& pattern, GeoQuery geoQuery);
|
||||||
|
SearchInfo(const RequestContext& request);
|
||||||
|
|
||||||
|
zim::Query getZimQuery(bool verbose) const;
|
||||||
|
|
||||||
|
friend bool operator<(const SearchInfo& l, const SearchInfo& r)
|
||||||
|
{
|
||||||
|
return std::tie(l.bookName, l.pattern, l.geoQuery)
|
||||||
|
< std::tie(r.bookName, r.pattern, r.geoQuery); // keep the same order
|
||||||
|
}
|
||||||
|
|
||||||
|
public: //data
|
||||||
|
std::string pattern;
|
||||||
|
GeoQuery geoQuery;
|
||||||
|
std::string bookName;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef kainjow::mustache::data MustacheData;
|
typedef kainjow::mustache::data MustacheData;
|
||||||
typedef ConcurrentCache<string, std::shared_ptr<zim::Searcher>> SearcherCache;
|
typedef ConcurrentCache<string, std::shared_ptr<zim::Searcher>> SearcherCache;
|
||||||
typedef ConcurrentCache<string, std::shared_ptr<zim::Search>> SearchCache;
|
typedef ConcurrentCache<SearchInfo, std::shared_ptr<zim::Search>> SearchCache;
|
||||||
typedef ConcurrentCache<string, std::shared_ptr<zim::SuggestionSearcher>> SuggestionSearcherCache;
|
typedef ConcurrentCache<string, std::shared_ptr<zim::SuggestionSearcher>> SuggestionSearcherCache;
|
||||||
|
|
||||||
class Entry;
|
class Entry;
|
||||||
|
|
Loading…
Reference in New Issue