add GeoShapeParser

This commit is contained in:
shzhulin3 2021-05-10 17:18:16 +08:00
parent fb6a8f3d02
commit a38cb98478
3 changed files with 187 additions and 0 deletions

View File

@ -25,6 +25,7 @@
#include "query/range_query_parser.h"
#include "query/match_query_parser.h"
#include "query/term_query_parser.h"
#include "query/geo_shape_parser.h"
#include <sstream>
using namespace std;
@ -230,6 +231,8 @@ int Component::GetQueryWord(uint32_t &m_has_gis, string &err_msg){
query_parser = new MatchQueryParser(m_appid, m_query["match"]);
} else if(m_query.isMember("term")){
query_parser = new TermQueryParser(m_appid, m_query["term"]);
} else if(m_query.isMember("geo_shape")){
query_parser = new GeoShapeParser(m_appid, m_query["geo_shape"]);
}
query_parser_res = new QueryParserRes();
int ret = query_parser->ParseContent(query_parser_res);

View File

@ -0,0 +1,141 @@
#include "geo_shape_parser.h"
#include "../db_manager.h"
#include <sstream>
const char* const POINTS ="points";
const int GEO_PRECISION = 6;
GeoShapeParser::GeoShapeParser(uint32_t a, Json::Value& v)
:appid(a),value(v)
{
}
GeoShapeParser::~GeoShapeParser(){
}
vector<double> GeoShapeParser::splitDouble(const string& src, string separate_character)
{
vector<double> strs;
//分割字符串的长度,这样就可以支持如“,,”多字符串的分隔符
int separate_characterLen = separate_character.size();
int lastPosition = 0, index = -1;
string str;
double pos = 0;
while (-1 != (index = src.find(separate_character, lastPosition)))
{
if (src.substr(lastPosition, index - lastPosition) != " ") {
str = src.substr(lastPosition, index - lastPosition);
pos = atof(str.c_str());
strs.push_back(pos);
}
lastPosition = index + separate_characterLen;
}
string lastString = src.substr(lastPosition);//截取最后一个分隔符后的内容
if (!lastString.empty() && lastString != " "){
pos = atof(lastString.c_str());
strs.push_back(pos);//如果最后一个分隔符后还有内容就入队
}
return strs;
}
void GeoShapeParser::SetErrMsg(QueryParserRes* query_parser_res, string err_msg){
log_error(err_msg.c_str());
query_parser_res->ErrMsg() = err_msg;
}
int GeoShapeParser::ParseContent(QueryParserRes* query_parser_res){
Json::Value::Members member = value.getMemberNames();
Json::Value::Members::iterator iter = member.begin();
if(iter == member.end()){ // 一个geo_shape下只对应一个字段
SetErrMsg(query_parser_res, "GeoShapeParser format error, content is null.");
return -RT_PARSE_CONTENT_ERROR;
}
set<double> lat_arr;
set<double> lon_arr;
string fieldname = *iter;
Json::Value field_value = value[fieldname];
if(field_value.isMember(POINTS)){
Json::Value points = field_value[POINTS];
if(points.isArray()){
for(int i = 0; i < (int)points.size(); i++){
double lat;
double lon;
Json::Value geo_value = points[i];
if(geo_value.isString()){
string geo_str = geo_value.asString();
vector<double> res = splitDouble(geo_str, ",");
if(res.size() >= 2){
lat = res[0];
lon = res[1];
} else {
SetErrMsg(query_parser_res, "GeoShapeParser format error.");
return -RT_PARSE_CONTENT_ERROR;
}
} else if (geo_value.isArray()){
if(geo_value.size() >= 2){
if(geo_value[0].isDouble()){
lon = geo_value[0].asDouble();
}
if(geo_value[1].isDouble()){
lat = geo_value[1].asDouble();
}
} else {
SetErrMsg(query_parser_res, "GeoShapeParser format error.");
return -RT_PARSE_CONTENT_ERROR;
}
} else if (geo_value.isObject()){
if(geo_value.isMember("lat") && geo_value["lat"].isDouble()){
lat = geo_value["lat"].asDouble();
} else {
SetErrMsg(query_parser_res, "GeoShapeParser lat format error.");
return -RT_PARSE_CONTENT_ERROR;
}
if(geo_value.isMember("lon") && geo_value["lon"].isDouble()){
lon = geo_value["lon"].asDouble();
} else {
SetErrMsg(query_parser_res, "GeoShapeParser lon format error.");
return -RT_PARSE_CONTENT_ERROR;
}
} else {
SetErrMsg(query_parser_res, "GeoShapeParser error, value is not string/array/object.");
return -RT_PARSE_CONTENT_ERROR;
}
lat_arr.insert(lat);
lon_arr.insert(lon);
}
} else {
SetErrMsg(query_parser_res, "GeoShapeParser error, points is not a array.");
return -RT_PARSE_CONTENT_ERROR;
}
} else {
SetErrMsg(query_parser_res, "GeoShapeParser error, no points content provide.");
return -RT_PARSE_CONTENT_ERROR;
}
if(lon_arr.size() > 0 && lat_arr.size() > 0){
vector<string> gisCode = GetArroundGeoHash(*lon_arr.rbegin(), *lon_arr.begin(), *lat_arr.rbegin(), *lat_arr.begin(), GEO_PRECISION);
if(gisCode.size() > 0){
vector<FieldInfo> fieldInfos;
uint32_t segment_tag = 0;
FieldInfo fieldInfo;
uint32_t field = DBManager::Instance()->GetWordField(segment_tag, appid, fieldname, fieldInfo);
if (field != 0 && segment_tag == 0) {
query_parser_res->HasGis() = 1;
for (size_t index = 0; index < gisCode.size(); index++) {
FieldInfo info;
info.field = fieldInfo.field;
info.field_type = fieldInfo.field_type;
info.segment_tag = fieldInfo.segment_tag;
info.word = gisCode[index];
fieldInfos.push_back(info);
}
}
if (fieldInfos.size() != 0) {
query_parser_res->FieldKeysMap().insert(make_pair(fieldInfo.field, fieldInfos));
}
}
}
return 0;
}

View File

@ -0,0 +1,43 @@
/*
* =====================================================================================
*
* Filename: geo_shape_parser.h
*
* Description: geo_shape_parser class definition.
*
* Version: 1.0
* Created: 08/05/2021
* Revision: none
* Compiler: gcc
*
* Author: zhulin, shzhulin3@jd.com
* Company: JD.com, Inc.
*
* =====================================================================================
*/
#ifndef __GEO_SHAPE_PARSER_H__
#define __GEO_SHAPE_PARSER_H__
#include "query_parser.h"
#include "json/json.h"
#include "geohash.h"
class GeoShapeParser : public QueryParser
{
public:
GeoShapeParser(uint32_t a, Json::Value& v);
~GeoShapeParser();
int ParseContent(QueryParserRes* query_parser_res);
private:
void SetErrMsg(QueryParserRes* query_parser_res, string err_msg);
vector<double> splitDouble(const string& src, string separate_character);
private:
uint32_t appid;
Json::Value value;
GeoPoint geo;
double distance;
};
#endif