Browse Source

add GeoShapeParser

shzhulin3 3 years ago
parent
commit
a38cb98478

+ 3 - 0
src/search_local/index_read/component.cc

@@ -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);

+ 141 - 0
src/search_local/index_read/query/geo_shape_parser.cc

@@ -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;
+}

+ 43 - 0
src/search_local/index_read/query/geo_shape_parser.h

@@ -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