/src/gdal/ogr/ogrsf_frmts/elastic/ogrelasticlayer.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: Elasticsearch Translator |
4 | | * Purpose: |
5 | | * Author: |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2011, Adam Estrada |
9 | | * Copyright (c) 2012-2016, Even Rouault <even dot rouault at spatialys.com> |
10 | | * |
11 | | * SPDX-License-Identifier: MIT |
12 | | ****************************************************************************/ |
13 | | |
14 | | #include "ogr_elastic.h" |
15 | | #include "cpl_conv.h" |
16 | | #include "cpl_minixml.h" |
17 | | #include "cpl_http.h" |
18 | | #include "ogr_api.h" |
19 | | #include "ogr_p.h" |
20 | | #include "ogr_swq.h" |
21 | | #include "ogrgeojsonwriter.h" |
22 | | #include "ogrlibjsonutils.h" |
23 | | #include "ogrgeojsongeometry.h" |
24 | | #include "ogr_geo_utils.h" |
25 | | |
26 | | #include <cstdlib> |
27 | | #include <set> |
28 | | |
29 | | /************************************************************************/ |
30 | | /* CPLGettimeofday() */ |
31 | | /************************************************************************/ |
32 | | |
33 | | #if defined(_WIN32) && !defined(__CYGWIN__) |
34 | | #include <sys/timeb.h> |
35 | | |
36 | | struct CPLTimeVal |
37 | | { |
38 | | time_t tv_sec; /* seconds */ |
39 | | long tv_usec; /* and microseconds */ |
40 | | }; |
41 | | |
42 | | static void CPLGettimeofday(struct CPLTimeVal *tp, void * /* timezonep*/) |
43 | | { |
44 | | struct _timeb theTime; |
45 | | |
46 | | _ftime(&theTime); |
47 | | tp->tv_sec = static_cast<time_t>(theTime.time); |
48 | | tp->tv_usec = theTime.millitm * 1000; |
49 | | } |
50 | | #else |
51 | | #include <sys/time.h> /* for gettimeofday() */ |
52 | | #define CPLTimeVal timeval |
53 | 0 | #define CPLGettimeofday(t, u) gettimeofday(t, u) |
54 | | #endif |
55 | | |
56 | | static double GetTimestamp() |
57 | 0 | { |
58 | 0 | struct CPLTimeVal tv; |
59 | 0 | CPLGettimeofday(&tv, nullptr); |
60 | 0 | return tv.tv_sec + tv.tv_usec * 1e-6; |
61 | 0 | } |
62 | | |
63 | | /************************************************************************/ |
64 | | /* OGRElasticLayer() */ |
65 | | /************************************************************************/ |
66 | | |
67 | | OGRElasticLayer::OGRElasticLayer(const char *pszLayerName, |
68 | | const char *pszIndexName, |
69 | | const char *pszMappingName, |
70 | | OGRElasticDataSource *poDS, |
71 | | CSLConstList papszOptions, |
72 | | const char *pszESSearch) |
73 | | : |
74 | | |
75 | 0 | m_poDS(poDS), m_osIndexName(pszIndexName ? pszIndexName : ""), |
76 | | // Types are no longer supported in Elasticsearch 7+. |
77 | 0 | m_osMappingName(poDS->m_nMajorVersion < 7 |
78 | 0 | ? pszMappingName ? pszMappingName : "" |
79 | 0 | : ""), |
80 | 0 | m_poFeatureDefn(new OGRFeatureDefn(pszLayerName)), |
81 | 0 | m_osWriteMapFilename( |
82 | 0 | CSLFetchNameValueDef(papszOptions, "WRITE_MAPPING", |
83 | 0 | poDS->m_pszWriteMap ? poDS->m_pszWriteMap : "")), |
84 | 0 | m_bStoreFields(CPLFetchBool(papszOptions, "STORE_FIELDS", false)), |
85 | 0 | m_osESSearch(pszESSearch ? pszESSearch : ""), |
86 | 0 | m_nBulkUpload(poDS->m_nBulkUpload), |
87 | 0 | m_osPrecision(CSLFetchNameValueDef(papszOptions, "GEOM_PRECISION", "")), |
88 | | // Undocumented. Only useful for developers. |
89 | 0 | m_bAddPretty(CPLTestBool(CPLGetConfigOption("ES_ADD_PRETTY", "FALSE"))), |
90 | 0 | m_bGeoShapeAsGeoJSON(EQUAL( |
91 | | CSLFetchNameValueDef(papszOptions, "GEO_SHAPE_ENCODING", "GeoJSON"), |
92 | | "GeoJSON")) |
93 | 0 | { |
94 | 0 | const char *pszESGeomType = |
95 | 0 | CSLFetchNameValue(papszOptions, "GEOM_MAPPING_TYPE"); |
96 | 0 | if (pszESGeomType != nullptr) |
97 | 0 | { |
98 | 0 | if (EQUAL(pszESGeomType, "GEO_POINT")) |
99 | 0 | m_eGeomTypeMapping = ES_GEOMTYPE_GEO_POINT; |
100 | 0 | else if (EQUAL(pszESGeomType, "GEO_SHAPE")) |
101 | 0 | m_eGeomTypeMapping = ES_GEOMTYPE_GEO_SHAPE; |
102 | 0 | } |
103 | |
|
104 | 0 | if (CPLFetchBool(papszOptions, "BULK_INSERT", true)) |
105 | 0 | { |
106 | 0 | m_nBulkUpload = |
107 | 0 | atoi(CSLFetchNameValueDef(papszOptions, "BULK_SIZE", "1000000")); |
108 | 0 | } |
109 | |
|
110 | 0 | const char *pszStoredFields = |
111 | 0 | CSLFetchNameValue(papszOptions, "STORED_FIELDS"); |
112 | 0 | if (pszStoredFields) |
113 | 0 | m_papszStoredFields = CSLTokenizeString2(pszStoredFields, ",", 0); |
114 | |
|
115 | 0 | const char *pszNotAnalyzedFields = |
116 | 0 | CSLFetchNameValue(papszOptions, "NOT_ANALYZED_FIELDS"); |
117 | 0 | if (pszNotAnalyzedFields) |
118 | 0 | m_papszNotAnalyzedFields = |
119 | 0 | CSLTokenizeString2(pszNotAnalyzedFields, ",", 0); |
120 | |
|
121 | 0 | const char *pszNotIndexedFields = |
122 | 0 | CSLFetchNameValue(papszOptions, "NOT_INDEXED_FIELDS"); |
123 | 0 | if (pszNotIndexedFields) |
124 | 0 | m_papszNotIndexedFields = |
125 | 0 | CSLTokenizeString2(pszNotIndexedFields, ",", 0); |
126 | |
|
127 | 0 | const char *pszFieldsWithRawValue = |
128 | 0 | CSLFetchNameValue(papszOptions, "FIELDS_WITH_RAW_VALUE"); |
129 | 0 | if (pszFieldsWithRawValue) |
130 | 0 | m_papszFieldsWithRawValue = |
131 | 0 | CSLTokenizeString2(pszFieldsWithRawValue, ",", 0); |
132 | |
|
133 | 0 | const char *pszSingleQueryTimeout = |
134 | 0 | CSLFetchNameValue(papszOptions, "SINGLE_QUERY_TIMEOUT"); |
135 | 0 | if (pszSingleQueryTimeout) |
136 | 0 | { |
137 | 0 | m_dfSingleQueryTimeout = CPLAtof(pszSingleQueryTimeout); |
138 | 0 | if (m_dfSingleQueryTimeout < 1 && m_dfSingleQueryTimeout >= 1e-3) |
139 | 0 | m_osSingleQueryTimeout = CPLSPrintf( |
140 | 0 | "%dms", static_cast<int>(m_dfSingleQueryTimeout * 1000)); |
141 | 0 | else if (m_dfSingleQueryTimeout >= 1) |
142 | 0 | m_osSingleQueryTimeout = |
143 | 0 | CPLSPrintf("%ds", static_cast<int>(m_dfSingleQueryTimeout)); |
144 | 0 | } |
145 | |
|
146 | 0 | m_osSingleQueryTerminateAfter = |
147 | 0 | CSLFetchNameValueDef(papszOptions, "SINGLE_QUERY_TERMINATE_AFTER", ""); |
148 | 0 | m_nSingleQueryTerminateAfter = CPLAtoGIntBig(m_osSingleQueryTerminateAfter); |
149 | |
|
150 | 0 | const char *pszFeatureIterationTimeout = |
151 | 0 | CSLFetchNameValue(papszOptions, "FEATURE_ITERATION_TIMEOUT"); |
152 | 0 | if (pszFeatureIterationTimeout) |
153 | 0 | { |
154 | 0 | m_dfFeatureIterationTimeout = CPLAtof(pszFeatureIterationTimeout); |
155 | 0 | } |
156 | 0 | m_nFeatureIterationTerminateAfter = CPLAtoGIntBig(CSLFetchNameValueDef( |
157 | 0 | papszOptions, "FEATURE_ITERATION_TERMINATE_AFTER", "")); |
158 | |
|
159 | 0 | SetDescription(m_poFeatureDefn->GetName()); |
160 | 0 | m_poFeatureDefn->Reference(); |
161 | 0 | m_poFeatureDefn->SetGeomType(wkbNone); |
162 | |
|
163 | 0 | AddFieldDefn("_id", OFTString, std::vector<CPLString>()); |
164 | |
|
165 | 0 | if (!m_osESSearch.empty()) |
166 | 0 | { |
167 | 0 | AddFieldDefn("_index", OFTString, std::vector<CPLString>()); |
168 | 0 | AddFieldDefn("_type", OFTString, std::vector<CPLString>()); |
169 | 0 | } |
170 | |
|
171 | 0 | OGRElasticLayer::ResetReading(); |
172 | 0 | } |
173 | | |
174 | | /************************************************************************/ |
175 | | /* OGRElasticLayer() */ |
176 | | /************************************************************************/ |
177 | | |
178 | | OGRElasticLayer::OGRElasticLayer(const char *pszLayerName, |
179 | | OGRElasticLayer *poReferenceLayer) |
180 | 0 | : OGRElasticLayer(pszLayerName, pszLayerName, |
181 | 0 | poReferenceLayer->m_osMappingName, |
182 | 0 | poReferenceLayer->m_poDS, nullptr) |
183 | 0 | { |
184 | 0 | m_bAddSourceIndexName = poReferenceLayer->m_poDS->m_bAddSourceIndexName; |
185 | |
|
186 | 0 | poReferenceLayer->CopyMembersTo(this); |
187 | 0 | auto poFeatureDefn = new OGRFeatureDefn(pszLayerName); |
188 | 0 | if (m_bAddSourceIndexName) |
189 | 0 | { |
190 | 0 | OGRFieldDefn oFieldDefn("_index", OFTString); |
191 | 0 | poFeatureDefn->AddFieldDefn(&oFieldDefn); |
192 | 0 | #if defined(__GNUC__) |
193 | 0 | #pragma GCC diagnostic push |
194 | 0 | #pragma GCC diagnostic ignored "-Wnull-dereference" |
195 | 0 | #endif |
196 | 0 | m_aaosFieldPaths.insert(m_aaosFieldPaths.begin(), |
197 | 0 | std::vector<CPLString>()); |
198 | 0 | #if defined(__GNUC__) |
199 | 0 | #pragma GCC diagnostic pop |
200 | 0 | #endif |
201 | 0 | for (auto &kv : m_aosMapToFieldIndex) |
202 | 0 | { |
203 | 0 | kv.second++; |
204 | 0 | } |
205 | 0 | } |
206 | |
|
207 | 0 | { |
208 | 0 | const int nFieldCount = m_poFeatureDefn->GetFieldCount(); |
209 | 0 | for (int i = 0; i < nFieldCount; i++) |
210 | 0 | poFeatureDefn->AddFieldDefn(m_poFeatureDefn->GetFieldDefn(i)); |
211 | 0 | } |
212 | |
|
213 | 0 | { |
214 | | // Remove the default geometry field created instantiation. |
215 | 0 | poFeatureDefn->DeleteGeomFieldDefn(0); |
216 | 0 | const int nGeomFieldCount = m_poFeatureDefn->GetGeomFieldCount(); |
217 | 0 | for (int i = 0; i < nGeomFieldCount; i++) |
218 | 0 | poFeatureDefn->AddGeomFieldDefn( |
219 | 0 | m_poFeatureDefn->GetGeomFieldDefn(i)); |
220 | 0 | } |
221 | |
|
222 | 0 | m_poFeatureDefn->Release(); |
223 | 0 | m_poFeatureDefn = poFeatureDefn; |
224 | 0 | m_poFeatureDefn->Reference(); |
225 | |
|
226 | 0 | CPLAssert(static_cast<int>(m_aaosFieldPaths.size()) == |
227 | 0 | m_poFeatureDefn->GetFieldCount()); |
228 | 0 | CPLAssert(static_cast<int>(m_aaosGeomFieldPaths.size()) == |
229 | 0 | m_poFeatureDefn->GetGeomFieldCount()); |
230 | 0 | } |
231 | | |
232 | | /************************************************************************/ |
233 | | /* CopyMembersTo() */ |
234 | | /************************************************************************/ |
235 | | |
236 | | void OGRElasticLayer::CopyMembersTo(OGRElasticLayer *poNew) |
237 | 0 | { |
238 | 0 | FinalizeFeatureDefn(); |
239 | |
|
240 | 0 | poNew->m_poFeatureDefn->Release(); |
241 | 0 | poNew->m_poFeatureDefn = |
242 | 0 | const_cast<OGRElasticLayer *>(this)->GetLayerDefn()->Clone(); |
243 | 0 | poNew->m_poFeatureDefn->Reference(); |
244 | 0 | poNew->m_bFeatureDefnFinalized = true; |
245 | 0 | poNew->m_osBulkContent = m_osBulkContent; |
246 | 0 | poNew->m_nBulkUpload = m_nBulkUpload; |
247 | 0 | poNew->m_osFID = m_osFID; |
248 | 0 | poNew->m_aaosFieldPaths = m_aaosFieldPaths; |
249 | 0 | poNew->m_aosMapToFieldIndex = m_aosMapToFieldIndex; |
250 | 0 | poNew->m_aaosGeomFieldPaths = m_aaosGeomFieldPaths; |
251 | 0 | poNew->m_aosMapToGeomFieldIndex = m_aosMapToGeomFieldIndex; |
252 | 0 | poNew->m_abIsGeoPoint = m_abIsGeoPoint; |
253 | 0 | poNew->m_eGeomTypeMapping = m_eGeomTypeMapping; |
254 | 0 | poNew->m_osPrecision = m_osPrecision; |
255 | 0 | poNew->m_papszNotAnalyzedFields = CSLDuplicate(m_papszNotAnalyzedFields); |
256 | 0 | poNew->m_papszNotIndexedFields = CSLDuplicate(m_papszNotIndexedFields); |
257 | 0 | poNew->m_papszFieldsWithRawValue = CSLDuplicate(m_papszFieldsWithRawValue); |
258 | 0 | poNew->m_bGeoShapeAsGeoJSON = m_bGeoShapeAsGeoJSON; |
259 | 0 | poNew->m_osSingleQueryTimeout = m_osSingleQueryTimeout; |
260 | 0 | poNew->m_dfSingleQueryTimeout = m_dfSingleQueryTimeout; |
261 | 0 | poNew->m_dfFeatureIterationTimeout = m_dfFeatureIterationTimeout; |
262 | 0 | poNew->m_nSingleQueryTerminateAfter = m_nSingleQueryTerminateAfter; |
263 | 0 | poNew->m_nFeatureIterationTerminateAfter = |
264 | 0 | m_nFeatureIterationTerminateAfter; |
265 | 0 | poNew->m_osSingleQueryTerminateAfter = m_osSingleQueryTerminateAfter; |
266 | 0 | } |
267 | | |
268 | | /************************************************************************/ |
269 | | /* Clone() */ |
270 | | /************************************************************************/ |
271 | | |
272 | | OGRElasticLayer *OGRElasticLayer::Clone() |
273 | 0 | { |
274 | 0 | OGRElasticLayer *poNew = |
275 | 0 | new OGRElasticLayer(m_poFeatureDefn->GetName(), m_osIndexName, |
276 | 0 | m_osMappingName, m_poDS, nullptr); |
277 | 0 | CopyMembersTo(poNew); |
278 | 0 | return poNew; |
279 | 0 | } |
280 | | |
281 | | /************************************************************************/ |
282 | | /* ~OGRElasticLayer() */ |
283 | | /************************************************************************/ |
284 | | |
285 | | OGRElasticLayer::~OGRElasticLayer() |
286 | 0 | { |
287 | 0 | OGRElasticLayer::SyncToDisk(); |
288 | |
|
289 | 0 | OGRElasticLayer::ResetReading(); |
290 | |
|
291 | 0 | json_object_put(m_poSpatialFilter); |
292 | 0 | json_object_put(m_poJSONFilter); |
293 | |
|
294 | 0 | for (int i = 0; i < (int)m_apoCT.size(); i++) |
295 | 0 | delete m_apoCT[i]; |
296 | |
|
297 | 0 | m_poFeatureDefn->Release(); |
298 | |
|
299 | 0 | CSLDestroy(m_papszStoredFields); |
300 | 0 | CSLDestroy(m_papszNotAnalyzedFields); |
301 | 0 | CSLDestroy(m_papszNotIndexedFields); |
302 | 0 | CSLDestroy(m_papszFieldsWithRawValue); |
303 | 0 | } |
304 | | |
305 | | /************************************************************************/ |
306 | | /* AddFieldDefn() */ |
307 | | /************************************************************************/ |
308 | | |
309 | | void OGRElasticLayer::AddFieldDefn(const char *pszName, OGRFieldType eType, |
310 | | const std::vector<CPLString> &aosPath, |
311 | | OGRFieldSubType eSubType) |
312 | 0 | { |
313 | 0 | OGRFieldDefn oFieldDefn(pszName, eType); |
314 | 0 | oFieldDefn.SetSubType(eSubType); |
315 | 0 | if (eSubType == OFSTBoolean) |
316 | 0 | oFieldDefn.SetWidth(1); |
317 | 0 | m_aaosFieldPaths.push_back(aosPath); |
318 | 0 | if (!aosPath.empty()) |
319 | 0 | m_aosMapToFieldIndex[BuildPathFromArray(aosPath)] = |
320 | 0 | m_poFeatureDefn->GetFieldCount(); |
321 | 0 | m_poFeatureDefn->AddFieldDefn(&oFieldDefn); |
322 | 0 | } |
323 | | |
324 | | /************************************************************************/ |
325 | | /* AddGeomFieldDefn() */ |
326 | | /************************************************************************/ |
327 | | |
328 | | void OGRElasticLayer::AddGeomFieldDefn(const char *pszName, |
329 | | OGRwkbGeometryType eType, |
330 | | const std::vector<CPLString> &aosPath, |
331 | | int bIsGeoPoint) |
332 | 0 | { |
333 | 0 | OGRGeomFieldDefn oFieldDefn(pszName, eType); |
334 | 0 | m_aaosGeomFieldPaths.push_back(aosPath); |
335 | 0 | m_aosMapToGeomFieldIndex[BuildPathFromArray(aosPath)] = |
336 | 0 | m_poFeatureDefn->GetGeomFieldCount(); |
337 | 0 | m_abIsGeoPoint.push_back(bIsGeoPoint); |
338 | |
|
339 | 0 | OGRSpatialReference *poSRS_WGS84 = new OGRSpatialReference(); |
340 | 0 | poSRS_WGS84->SetFromUserInput(SRS_WKT_WGS84_LAT_LONG); |
341 | 0 | poSRS_WGS84->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
342 | 0 | oFieldDefn.SetSpatialRef(poSRS_WGS84); |
343 | 0 | poSRS_WGS84->Dereference(); |
344 | |
|
345 | 0 | m_poFeatureDefn->AddGeomFieldDefn(&oFieldDefn); |
346 | |
|
347 | 0 | m_apoCT.push_back(nullptr); |
348 | 0 | } |
349 | | |
350 | | /************************************************************************/ |
351 | | /* GetGeomFieldProperties() */ |
352 | | /************************************************************************/ |
353 | | |
354 | | void OGRElasticLayer::GetGeomFieldProperties(int iGeomField, |
355 | | std::vector<CPLString> &aosPath, |
356 | | bool &bIsGeoPoint) |
357 | 0 | { |
358 | 0 | aosPath = m_aaosGeomFieldPaths[iGeomField]; |
359 | 0 | bIsGeoPoint = CPL_TO_BOOL(m_abIsGeoPoint[iGeomField]); |
360 | 0 | } |
361 | | |
362 | | /************************************************************************/ |
363 | | /* InitFeatureDefnFromMapping() */ |
364 | | /************************************************************************/ |
365 | | |
366 | | void OGRElasticLayer::InitFeatureDefnFromMapping( |
367 | | json_object *poSchema, const char *pszPrefix, |
368 | | const std::vector<CPLString> &aosPath) |
369 | 0 | { |
370 | 0 | json_object *poTopProperties = |
371 | 0 | CPL_json_object_object_get(poSchema, "properties"); |
372 | 0 | if (poTopProperties == nullptr || |
373 | 0 | json_object_get_type(poTopProperties) != json_type_object) |
374 | 0 | return; |
375 | 0 | json_object_iter it; |
376 | 0 | it.key = nullptr; |
377 | 0 | it.val = nullptr; |
378 | 0 | it.entry = nullptr; |
379 | 0 | json_object_object_foreachC(poTopProperties, it) |
380 | 0 | { |
381 | 0 | json_object *poProperties = |
382 | 0 | CPL_json_object_object_get(it.val, "properties"); |
383 | 0 | if (poProperties && |
384 | 0 | json_object_get_type(poProperties) == json_type_object) |
385 | 0 | { |
386 | 0 | json_object *poType = |
387 | 0 | json_ex_get_object_by_path(poProperties, "coordinates.type"); |
388 | 0 | if (poType && json_object_get_type(poType) == json_type_string && |
389 | 0 | strcmp(json_object_get_string(poType), "geo_point") == 0) |
390 | 0 | { |
391 | 0 | CPLString osFieldName; |
392 | 0 | if (pszPrefix[0]) |
393 | 0 | { |
394 | 0 | osFieldName = pszPrefix; |
395 | 0 | osFieldName += "."; |
396 | 0 | } |
397 | 0 | osFieldName += it.key; |
398 | |
|
399 | 0 | if (m_poFeatureDefn->GetGeomFieldIndex(osFieldName) < 0) |
400 | 0 | { |
401 | 0 | std::vector<CPLString> aosNewPaths = aosPath; |
402 | 0 | aosNewPaths.push_back(osFieldName); |
403 | 0 | aosNewPaths.push_back("coordinates"); |
404 | |
|
405 | 0 | AddGeomFieldDefn(osFieldName, wkbPoint, aosNewPaths, TRUE); |
406 | 0 | } |
407 | |
|
408 | 0 | continue; |
409 | 0 | } |
410 | | |
411 | 0 | if (aosPath.empty() && m_osMappingName == "FeatureCollection" && |
412 | 0 | strcmp(it.key, "properties") == 0) |
413 | 0 | { |
414 | 0 | std::vector<CPLString> aosNewPaths = aosPath; |
415 | 0 | aosNewPaths.push_back(it.key); |
416 | |
|
417 | 0 | InitFeatureDefnFromMapping(it.val, pszPrefix, aosNewPaths); |
418 | |
|
419 | 0 | continue; |
420 | 0 | } |
421 | 0 | else if (m_poDS->m_bFlattenNestedAttributes) |
422 | 0 | { |
423 | 0 | std::vector<CPLString> aosNewPaths = aosPath; |
424 | 0 | aosNewPaths.push_back(it.key); |
425 | |
|
426 | 0 | CPLString osPrefix; |
427 | 0 | if (pszPrefix[0]) |
428 | 0 | { |
429 | 0 | osPrefix = pszPrefix; |
430 | 0 | osPrefix += "."; |
431 | 0 | } |
432 | 0 | osPrefix += it.key; |
433 | |
|
434 | 0 | InitFeatureDefnFromMapping(it.val, osPrefix, aosNewPaths); |
435 | |
|
436 | 0 | continue; |
437 | 0 | } |
438 | 0 | } |
439 | | |
440 | 0 | if (aosPath.empty() && EQUAL(it.key, m_poDS->GetFID())) |
441 | 0 | { |
442 | 0 | m_osFID = it.key; |
443 | 0 | } |
444 | 0 | else |
445 | 0 | { |
446 | 0 | CreateFieldFromSchema(it.key, pszPrefix, aosPath, it.val); |
447 | 0 | } |
448 | 0 | } |
449 | |
|
450 | 0 | if (aosPath.empty()) |
451 | 0 | { |
452 | 0 | json_object *poMeta = CPL_json_object_object_get(poSchema, "_meta"); |
453 | 0 | if (poMeta && json_object_get_type(poMeta) == json_type_object) |
454 | 0 | { |
455 | 0 | json_object *poFID = CPL_json_object_object_get(poMeta, "fid"); |
456 | 0 | if (poFID && json_object_get_type(poFID) == json_type_string) |
457 | 0 | m_osFID = json_object_get_string(poFID); |
458 | |
|
459 | 0 | json_object *poGeomFields = |
460 | 0 | CPL_json_object_object_get(poMeta, "geomfields"); |
461 | 0 | if (poGeomFields && |
462 | 0 | json_object_get_type(poGeomFields) == json_type_object) |
463 | 0 | { |
464 | 0 | for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); i++) |
465 | 0 | { |
466 | 0 | json_object *poObj = CPL_json_object_object_get( |
467 | 0 | poGeomFields, |
468 | 0 | m_poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef()); |
469 | 0 | if (poObj && |
470 | 0 | json_object_get_type(poObj) == json_type_string) |
471 | 0 | { |
472 | 0 | OGRwkbGeometryType eType = |
473 | 0 | OGRFromOGCGeomType(json_object_get_string(poObj)); |
474 | 0 | if (eType != wkbUnknown) |
475 | 0 | m_poFeatureDefn->GetGeomFieldDefn(i)->SetType( |
476 | 0 | eType); |
477 | 0 | } |
478 | 0 | } |
479 | 0 | } |
480 | |
|
481 | 0 | json_object *poFields = |
482 | 0 | CPL_json_object_object_get(poMeta, "fields"); |
483 | 0 | if (poFields && json_object_get_type(poFields) == json_type_object) |
484 | 0 | { |
485 | 0 | for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++) |
486 | 0 | { |
487 | 0 | json_object *poObj = CPL_json_object_object_get( |
488 | 0 | poFields, |
489 | 0 | m_poFeatureDefn->GetFieldDefn(i)->GetNameRef()); |
490 | 0 | if (poObj && |
491 | 0 | json_object_get_type(poObj) == json_type_string) |
492 | 0 | { |
493 | 0 | for (int j = 0; j <= OFTMaxType; j++) |
494 | 0 | { |
495 | 0 | if (EQUAL(OGR_GetFieldTypeName((OGRFieldType)j), |
496 | 0 | json_object_get_string(poObj))) |
497 | 0 | { |
498 | 0 | m_poFeatureDefn->GetFieldDefn(i)->SetType( |
499 | 0 | (OGRFieldType)j); |
500 | 0 | break; |
501 | 0 | } |
502 | 0 | } |
503 | 0 | } |
504 | 0 | } |
505 | 0 | } |
506 | 0 | } |
507 | 0 | } |
508 | 0 | } |
509 | | |
510 | | /************************************************************************/ |
511 | | /* CreateFieldFromSchema() */ |
512 | | /************************************************************************/ |
513 | | |
514 | | void OGRElasticLayer::CreateFieldFromSchema(const char *pszName, |
515 | | const char *pszPrefix, |
516 | | std::vector<CPLString> aosPath, |
517 | | json_object *poObj) |
518 | 0 | { |
519 | 0 | const char *pszType = ""; |
520 | 0 | json_object *poType = CPL_json_object_object_get(poObj, "type"); |
521 | 0 | if (poType && json_object_get_type(poType) == json_type_string) |
522 | 0 | { |
523 | 0 | pszType = json_object_get_string(poType); |
524 | 0 | } |
525 | |
|
526 | 0 | CPLString osFieldName; |
527 | 0 | if (pszPrefix[0]) |
528 | 0 | { |
529 | 0 | osFieldName = pszPrefix; |
530 | 0 | osFieldName += "."; |
531 | 0 | } |
532 | 0 | osFieldName += pszName; |
533 | |
|
534 | 0 | if (EQUAL(pszType, "geo_point") || EQUAL(pszType, "geo_shape")) |
535 | 0 | { |
536 | 0 | if (m_poFeatureDefn->GetGeomFieldIndex(osFieldName) >= 0) |
537 | 0 | return; |
538 | | |
539 | 0 | aosPath.push_back(pszName); |
540 | 0 | AddGeomFieldDefn(osFieldName, |
541 | 0 | EQUAL(pszType, "geo_point") ? wkbPoint : wkbUnknown, |
542 | 0 | aosPath, EQUAL(pszType, "geo_point")); |
543 | 0 | } |
544 | 0 | else if (!(aosPath.empty() && m_osMappingName == "FeatureCollection")) |
545 | 0 | { |
546 | 0 | if (m_poFeatureDefn->GetFieldIndex(osFieldName) >= 0) |
547 | 0 | return; |
548 | | |
549 | 0 | OGRFieldType eType = OFTString; |
550 | 0 | OGRFieldSubType eSubType = OFSTNone; |
551 | 0 | if (EQUAL(pszType, "integer")) |
552 | 0 | eType = OFTInteger; |
553 | 0 | else if (EQUAL(pszType, "boolean")) |
554 | 0 | { |
555 | 0 | eType = OFTInteger; |
556 | 0 | eSubType = OFSTBoolean; |
557 | 0 | } |
558 | 0 | else if (EQUAL(pszType, "long")) |
559 | 0 | eType = OFTInteger64; |
560 | 0 | else if (EQUAL(pszType, "float")) |
561 | 0 | eType = OFTReal; |
562 | 0 | else if (EQUAL(pszType, "double")) |
563 | 0 | eType = OFTReal; |
564 | 0 | else if (EQUAL(pszType, "date")) |
565 | 0 | { |
566 | 0 | eType = OFTDateTime; |
567 | 0 | json_object *poFormat = CPL_json_object_object_get(poObj, "format"); |
568 | 0 | if (poFormat && json_object_get_type(poFormat) == json_type_string) |
569 | 0 | { |
570 | 0 | const char *pszFormat = json_object_get_string(poFormat); |
571 | 0 | if (EQUAL(pszFormat, "HH:mm:ss.SSS") || |
572 | 0 | EQUAL(pszFormat, "time")) |
573 | 0 | eType = OFTTime; |
574 | 0 | else if (EQUAL(pszFormat, "yyyy/MM/dd") || |
575 | 0 | EQUAL(pszFormat, "date")) |
576 | 0 | eType = OFTDate; |
577 | 0 | } |
578 | 0 | } |
579 | 0 | else if (EQUAL(pszType, "binary")) |
580 | 0 | eType = OFTBinary; |
581 | 0 | else if (EQUAL(pszType, "string")) // ES < 5.0 |
582 | 0 | { |
583 | 0 | json_object *poIndex = CPL_json_object_object_get(poObj, "index"); |
584 | 0 | if (poIndex && json_object_get_type(poIndex) == json_type_string) |
585 | 0 | { |
586 | 0 | const char *pszIndex = json_object_get_string(poIndex); |
587 | 0 | if (EQUAL(pszIndex, "not_analyzed")) |
588 | 0 | { |
589 | 0 | m_papszNotAnalyzedFields = |
590 | 0 | CSLAddString(m_papszNotAnalyzedFields, osFieldName); |
591 | 0 | } |
592 | 0 | } |
593 | 0 | } |
594 | 0 | else if (EQUAL(pszType, "keyword")) // ES >= 5.0 |
595 | 0 | { |
596 | 0 | m_papszNotAnalyzedFields = |
597 | 0 | CSLAddString(m_papszNotAnalyzedFields, osFieldName); |
598 | 0 | } |
599 | |
|
600 | 0 | aosPath.push_back(pszName); |
601 | 0 | AddFieldDefn(osFieldName, eType, aosPath, eSubType); |
602 | |
|
603 | 0 | json_object *poFields = CPL_json_object_object_get(poObj, "fields"); |
604 | 0 | if (poFields && json_object_get_type(poFields) == json_type_object) |
605 | 0 | { |
606 | 0 | json_object *poRaw = CPL_json_object_object_get(poFields, "raw"); |
607 | 0 | if (poRaw && json_object_get_type(poRaw) == json_type_object) |
608 | 0 | { |
609 | 0 | json_object *poRawType = |
610 | 0 | CPL_json_object_object_get(poRaw, "type"); |
611 | 0 | if (poRawType && |
612 | 0 | json_object_get_type(poRawType) == json_type_string) |
613 | 0 | { |
614 | 0 | const char *pszRawType = json_object_get_string(poRawType); |
615 | 0 | if (EQUAL(pszRawType, "keyword")) // ES >= 5.0 |
616 | 0 | { |
617 | 0 | m_papszFieldsWithRawValue = CSLAddString( |
618 | 0 | m_papszFieldsWithRawValue, osFieldName); |
619 | 0 | } |
620 | 0 | else if (EQUAL(pszRawType, "string")) // ES < 5.0 |
621 | 0 | { |
622 | 0 | json_object *poRawIndex = |
623 | 0 | CPL_json_object_object_get(poRaw, "index"); |
624 | 0 | if (poRawIndex && json_object_get_type(poRawIndex) == |
625 | 0 | json_type_string) |
626 | 0 | { |
627 | 0 | const char *pszRawIndex = |
628 | 0 | json_object_get_string(poRawIndex); |
629 | 0 | if (EQUAL(pszRawIndex, "not_analyzed")) |
630 | 0 | { |
631 | 0 | m_papszFieldsWithRawValue = CSLAddString( |
632 | 0 | m_papszFieldsWithRawValue, osFieldName); |
633 | 0 | } |
634 | 0 | } |
635 | 0 | } |
636 | 0 | } |
637 | 0 | } |
638 | 0 | } |
639 | 0 | } |
640 | 0 | } |
641 | | |
642 | | /************************************************************************/ |
643 | | /* FinalizeFeatureDefn() */ |
644 | | /************************************************************************/ |
645 | | |
646 | | void OGRElasticLayer::FinalizeFeatureDefn(bool bReadFeatures) |
647 | 0 | { |
648 | 0 | if (m_bFeatureDefnFinalized) |
649 | 0 | return; |
650 | | |
651 | 0 | m_bFeatureDefnFinalized = true; |
652 | |
|
653 | 0 | int nFeatureCountToEstablishFeatureDefn = |
654 | 0 | m_poDS->m_nFeatureCountToEstablishFeatureDefn; |
655 | 0 | if (!m_osESSearch.empty() && nFeatureCountToEstablishFeatureDefn <= 0) |
656 | 0 | nFeatureCountToEstablishFeatureDefn = 1; |
657 | 0 | std::set<std::pair<CPLString, CPLString>> oVisited; |
658 | |
|
659 | 0 | if (bReadFeatures && nFeatureCountToEstablishFeatureDefn != 0) |
660 | 0 | { |
661 | | // CPLDebug("ES", "Try to get %d features to establish feature |
662 | | // definition", |
663 | | // FeatureCountToEstablishFeatureDefn); |
664 | 0 | bool bFirst = true; |
665 | 0 | int nAlreadyQueried = 0; |
666 | 0 | while (true) |
667 | 0 | { |
668 | 0 | CPLString osRequest; |
669 | 0 | CPLString osPostData; |
670 | 0 | if (bFirst) |
671 | 0 | { |
672 | 0 | bFirst = false; |
673 | 0 | if (!m_osESSearch.empty()) |
674 | 0 | { |
675 | 0 | osRequest = |
676 | 0 | CPLSPrintf("%s/_search?scroll=1m&size=%d", |
677 | 0 | m_poDS->GetURL(), m_poDS->m_nBatchSize); |
678 | 0 | osPostData = m_osESSearch; |
679 | 0 | } |
680 | 0 | else |
681 | 0 | { |
682 | 0 | osRequest = BuildMappingURL(false); |
683 | 0 | osRequest += CPLSPrintf("/_search?scroll=1m&size=%d", |
684 | 0 | m_poDS->m_nBatchSize); |
685 | 0 | } |
686 | 0 | } |
687 | 0 | else |
688 | 0 | { |
689 | 0 | if (m_osScrollID.empty()) |
690 | 0 | break; |
691 | 0 | osRequest = |
692 | 0 | CPLSPrintf("%s/_search/scroll?scroll=1m&scroll_id=%s", |
693 | 0 | m_poDS->GetURL(), m_osScrollID.c_str()); |
694 | 0 | } |
695 | | |
696 | 0 | if (m_bAddPretty) |
697 | 0 | osRequest += "&pretty"; |
698 | 0 | json_object *poResponse = m_poDS->RunRequest(osRequest, osPostData); |
699 | 0 | if (poResponse == nullptr) |
700 | 0 | { |
701 | 0 | break; |
702 | 0 | } |
703 | 0 | json_object *poScrollID = |
704 | 0 | CPL_json_object_object_get(poResponse, "_scroll_id"); |
705 | 0 | if (poScrollID) |
706 | 0 | { |
707 | 0 | const char *pszScrollID = json_object_get_string(poScrollID); |
708 | 0 | if (pszScrollID) |
709 | 0 | m_osScrollID = pszScrollID; |
710 | 0 | } |
711 | |
|
712 | 0 | json_object *poHits = |
713 | 0 | json_ex_get_object_by_path(poResponse, "hits.hits"); |
714 | 0 | if (poHits == nullptr || |
715 | 0 | json_object_get_type(poHits) != json_type_array) |
716 | 0 | { |
717 | 0 | json_object_put(poResponse); |
718 | 0 | break; |
719 | 0 | } |
720 | 0 | const auto nHits = json_object_array_length(poHits); |
721 | 0 | if (nHits == 0) |
722 | 0 | { |
723 | 0 | m_osScrollID = ""; |
724 | 0 | json_object_put(poResponse); |
725 | 0 | break; |
726 | 0 | } |
727 | 0 | for (auto i = decltype(nHits){0}; i < nHits; i++) |
728 | 0 | { |
729 | 0 | json_object *poHit = json_object_array_get_idx(poHits, i); |
730 | 0 | if (poHit == nullptr || |
731 | 0 | json_object_get_type(poHit) != json_type_object) |
732 | 0 | { |
733 | 0 | continue; |
734 | 0 | } |
735 | 0 | json_object *poSource = |
736 | 0 | CPL_json_object_object_get(poHit, "_source"); |
737 | 0 | if (poSource == nullptr || |
738 | 0 | json_object_get_type(poSource) != json_type_object) |
739 | 0 | { |
740 | 0 | continue; |
741 | 0 | } |
742 | | |
743 | 0 | if (!m_osESSearch.empty()) |
744 | 0 | { |
745 | 0 | json_object *poIndex = |
746 | 0 | CPL_json_object_object_get(poHit, "_index"); |
747 | 0 | if (poIndex == nullptr || |
748 | 0 | json_object_get_type(poIndex) != json_type_string) |
749 | 0 | break; |
750 | 0 | if (m_poDS->m_nMajorVersion < 7) |
751 | 0 | { |
752 | 0 | json_object *poType = |
753 | 0 | CPL_json_object_object_get(poHit, "_type"); |
754 | 0 | if (poType == nullptr || |
755 | 0 | json_object_get_type(poType) != json_type_string) |
756 | 0 | break; |
757 | 0 | m_osMappingName = json_object_get_string(poType); |
758 | 0 | } |
759 | 0 | CPLString osIndex(json_object_get_string(poIndex)); |
760 | |
|
761 | 0 | if (oVisited.find(std::pair<CPLString, CPLString>( |
762 | 0 | osIndex, m_osMappingName)) == oVisited.end()) |
763 | 0 | { |
764 | 0 | oVisited.insert(std::pair<CPLString, CPLString>( |
765 | 0 | osIndex, m_osMappingName)); |
766 | |
|
767 | 0 | CPLString osURL = |
768 | 0 | CPLSPrintf("%s/%s/_mapping", m_poDS->GetURL(), |
769 | 0 | osIndex.c_str()); |
770 | 0 | if (m_poDS->m_nMajorVersion < 7) |
771 | 0 | osURL += CPLSPrintf("/%s", m_osMappingName.c_str()); |
772 | 0 | osURL += "?pretty"; |
773 | |
|
774 | 0 | json_object *poMappingRes = m_poDS->RunRequest(osURL); |
775 | 0 | if (poMappingRes) |
776 | 0 | { |
777 | 0 | json_object *poLayerObj = |
778 | 0 | CPL_json_object_object_get(poMappingRes, |
779 | 0 | osIndex); |
780 | 0 | json_object *poMappings = nullptr; |
781 | 0 | if (poLayerObj && |
782 | 0 | json_object_get_type(poLayerObj) == |
783 | 0 | json_type_object) |
784 | 0 | poMappings = CPL_json_object_object_get( |
785 | 0 | poLayerObj, "mappings"); |
786 | 0 | if (poMappings && |
787 | 0 | json_object_get_type(poMappings) == |
788 | 0 | json_type_object) |
789 | 0 | { |
790 | 0 | json_object *poMapping = |
791 | 0 | m_poDS->m_nMajorVersion < 7 |
792 | 0 | ? CPL_json_object_object_get( |
793 | 0 | poMappings, m_osMappingName) |
794 | 0 | : poMappings; |
795 | 0 | if (poMapping) |
796 | 0 | { |
797 | 0 | InitFeatureDefnFromMapping( |
798 | 0 | poMapping, "", |
799 | 0 | std::vector<CPLString>()); |
800 | 0 | } |
801 | 0 | } |
802 | 0 | json_object_put(poMappingRes); |
803 | 0 | } |
804 | 0 | } |
805 | 0 | } |
806 | | |
807 | 0 | json_object_iter it; |
808 | 0 | it.key = nullptr; |
809 | 0 | it.val = nullptr; |
810 | 0 | it.entry = nullptr; |
811 | 0 | json_object_object_foreachC(poSource, it) |
812 | 0 | { |
813 | 0 | if (!m_osFID.empty()) |
814 | 0 | { |
815 | 0 | if (EQUAL(it.key, m_osFID)) |
816 | 0 | continue; |
817 | 0 | } |
818 | 0 | else if (EQUAL(it.key, m_poDS->GetFID())) |
819 | 0 | { |
820 | 0 | m_osFID = it.key; |
821 | 0 | continue; |
822 | 0 | } |
823 | | |
824 | 0 | if (m_osMappingName == "FeatureCollection") |
825 | 0 | { |
826 | 0 | if (strcmp(it.key, "properties") == 0 && |
827 | 0 | json_object_get_type(it.val) == json_type_object) |
828 | 0 | { |
829 | 0 | json_object_iter it2; |
830 | 0 | it2.key = nullptr; |
831 | 0 | it2.val = nullptr; |
832 | 0 | it2.entry = nullptr; |
833 | 0 | json_object_object_foreachC(it.val, it2) |
834 | 0 | { |
835 | 0 | std::vector<CPLString> aosPath; |
836 | 0 | aosPath.push_back("properties"); |
837 | 0 | AddOrUpdateField(it2.key, it2.key, it2.val, '.', |
838 | 0 | aosPath); |
839 | 0 | } |
840 | 0 | } |
841 | 0 | } |
842 | 0 | else |
843 | 0 | { |
844 | 0 | std::vector<CPLString> aosPath; |
845 | 0 | AddOrUpdateField(it.key, it.key, it.val, '.', aosPath); |
846 | 0 | } |
847 | 0 | } |
848 | |
|
849 | 0 | nAlreadyQueried++; |
850 | 0 | if (nFeatureCountToEstablishFeatureDefn > 0 && |
851 | 0 | nAlreadyQueried >= nFeatureCountToEstablishFeatureDefn) |
852 | 0 | { |
853 | 0 | break; |
854 | 0 | } |
855 | 0 | } |
856 | |
|
857 | 0 | json_object_put(poResponse); |
858 | |
|
859 | 0 | if (nFeatureCountToEstablishFeatureDefn > 0 && |
860 | 0 | nAlreadyQueried >= nFeatureCountToEstablishFeatureDefn) |
861 | 0 | { |
862 | 0 | break; |
863 | 0 | } |
864 | 0 | } |
865 | |
|
866 | 0 | ResetReading(); |
867 | 0 | } |
868 | |
|
869 | 0 | if (m_poDS->m_bJSonField) |
870 | 0 | { |
871 | 0 | AddFieldDefn("_json", OFTString, std::vector<CPLString>()); |
872 | 0 | } |
873 | 0 | } |
874 | | |
875 | | /************************************************************************/ |
876 | | /* BuildPathFromArray() */ |
877 | | /************************************************************************/ |
878 | | |
879 | | CPLString |
880 | | OGRElasticLayer::BuildPathFromArray(const std::vector<CPLString> &aosPath) |
881 | 0 | { |
882 | 0 | CPLString osPath(aosPath[0]); |
883 | 0 | for (size_t i = 1; i < aosPath.size(); i++) |
884 | 0 | { |
885 | 0 | osPath += "."; |
886 | 0 | osPath += aosPath[i]; |
887 | 0 | } |
888 | 0 | return osPath; |
889 | 0 | } |
890 | | |
891 | | /************************************************************************/ |
892 | | /* GetOGRGeomTypeFromES() */ |
893 | | /************************************************************************/ |
894 | | |
895 | | static OGRwkbGeometryType GetOGRGeomTypeFromES(const char *pszType) |
896 | 0 | { |
897 | 0 | if (EQUAL(pszType, "envelope")) |
898 | 0 | return wkbPolygon; |
899 | 0 | if (EQUAL(pszType, "circle")) |
900 | 0 | return wkbPolygon; |
901 | 0 | return OGRFromOGCGeomType(pszType); |
902 | 0 | } |
903 | | |
904 | | /************************************************************************/ |
905 | | /* AddOrUpdateField() */ |
906 | | /************************************************************************/ |
907 | | |
908 | | void OGRElasticLayer::AddOrUpdateField(const char *pszAttrName, |
909 | | const char *pszKey, json_object *poObj, |
910 | | char chNestedAttributeSeparator, |
911 | | std::vector<CPLString> &aosPath) |
912 | 0 | { |
913 | 0 | json_type eJSONType = json_object_get_type(poObj); |
914 | 0 | if (eJSONType == json_type_null) |
915 | 0 | return; |
916 | | |
917 | 0 | if (eJSONType == json_type_object) |
918 | 0 | { |
919 | 0 | json_object *poType = CPL_json_object_object_get(poObj, "type"); |
920 | 0 | OGRwkbGeometryType eGeomType; |
921 | 0 | if (poType && json_object_get_type(poType) == json_type_string && |
922 | 0 | (eGeomType = GetOGRGeomTypeFromES( |
923 | 0 | json_object_get_string(poType))) != wkbUnknown && |
924 | 0 | CPL_json_object_object_get( |
925 | 0 | poObj, (eGeomType == wkbGeometryCollection) ? "geometries" |
926 | 0 | : "coordinates")) |
927 | 0 | { |
928 | 0 | int nIndex = m_poFeatureDefn->GetGeomFieldIndex(pszAttrName); |
929 | 0 | if (nIndex < 0) |
930 | 0 | { |
931 | 0 | aosPath.push_back(pszKey); |
932 | 0 | AddGeomFieldDefn(pszAttrName, eGeomType, aosPath, FALSE); |
933 | 0 | } |
934 | 0 | else |
935 | 0 | { |
936 | 0 | OGRGeomFieldDefn *poFDefn = |
937 | 0 | m_poFeatureDefn->GetGeomFieldDefn(nIndex); |
938 | 0 | if (poFDefn->GetType() != eGeomType) |
939 | 0 | poFDefn->SetType(wkbUnknown); |
940 | 0 | } |
941 | 0 | } |
942 | 0 | else if (m_poDS->m_bFlattenNestedAttributes) |
943 | 0 | { |
944 | 0 | if (m_poFeatureDefn->GetGeomFieldIndex(pszAttrName) >= 0) |
945 | 0 | return; |
946 | 0 | aosPath.push_back(pszKey); |
947 | |
|
948 | 0 | json_object_iter it; |
949 | 0 | it.key = nullptr; |
950 | 0 | it.val = nullptr; |
951 | 0 | it.entry = nullptr; |
952 | 0 | json_object_object_foreachC(poObj, it) |
953 | 0 | { |
954 | 0 | char szSeparator[2]; |
955 | 0 | szSeparator[0] = chNestedAttributeSeparator; |
956 | 0 | szSeparator[1] = 0; |
957 | 0 | CPLString osAttrName( |
958 | 0 | CPLSPrintf("%s%s%s", pszAttrName, szSeparator, it.key)); |
959 | |
|
960 | 0 | std::vector<CPLString> aosNewPaths(aosPath); |
961 | 0 | AddOrUpdateField(osAttrName, it.key, it.val, |
962 | 0 | chNestedAttributeSeparator, aosNewPaths); |
963 | 0 | } |
964 | 0 | return; |
965 | 0 | } |
966 | 0 | } |
967 | | /*else if( eJSONType == json_type_array ) |
968 | | { |
969 | | if( m_poFeatureDefn->GetGeomFieldIndex(pszAttrName) >= 0 ) |
970 | | return; |
971 | | }*/ |
972 | | |
973 | 0 | if (m_poFeatureDefn->GetGeomFieldIndex(pszAttrName) >= 0) |
974 | 0 | return; |
975 | | |
976 | 0 | OGRFieldSubType eNewSubType; |
977 | 0 | OGRFieldType eNewType = GeoJSONPropertyToFieldType(poObj, eNewSubType); |
978 | |
|
979 | 0 | int nIndex = m_poFeatureDefn->GetFieldIndex(pszAttrName); |
980 | 0 | OGRFieldDefn *poFDefn = nullptr; |
981 | 0 | if (nIndex >= 0) |
982 | 0 | poFDefn = m_poFeatureDefn->GetFieldDefn(nIndex); |
983 | 0 | if ((poFDefn == nullptr && eNewType == OFTString) || |
984 | 0 | (poFDefn != nullptr && |
985 | 0 | (poFDefn->GetType() == OFTDate || poFDefn->GetType() == OFTDateTime || |
986 | 0 | poFDefn->GetType() == OFTTime))) |
987 | 0 | { |
988 | 0 | int nYear = 0; |
989 | 0 | int nMonth = 0; |
990 | 0 | int nDay = 0; |
991 | 0 | int nHour = 0; |
992 | 0 | int nMinute = 0; |
993 | 0 | float fSecond = 0.0f; |
994 | 0 | if (sscanf(json_object_get_string(poObj), "%04d/%02d/%02d %02d:%02d", |
995 | 0 | &nYear, &nMonth, &nDay, &nHour, &nMinute) == 5 || |
996 | 0 | sscanf(json_object_get_string(poObj), "%04d-%02d-%02dT%02d:%02d", |
997 | 0 | &nYear, &nMonth, &nDay, &nHour, &nMinute) == 5) |
998 | 0 | { |
999 | 0 | eNewType = OFTDateTime; |
1000 | 0 | } |
1001 | 0 | else if (sscanf(json_object_get_string(poObj), "%04d/%02d/%02d", &nYear, |
1002 | 0 | &nMonth, &nDay) == 3 || |
1003 | 0 | sscanf(json_object_get_string(poObj), "%04d-%02d-%02d", &nYear, |
1004 | 0 | &nMonth, &nDay) == 3) |
1005 | 0 | { |
1006 | 0 | eNewType = OFTDate; |
1007 | 0 | } |
1008 | 0 | else if (sscanf(json_object_get_string(poObj), "%02d:%02d:%f", &nHour, |
1009 | 0 | &nMinute, &fSecond) == 3) |
1010 | 0 | { |
1011 | 0 | eNewType = OFTTime; |
1012 | 0 | } |
1013 | 0 | } |
1014 | |
|
1015 | 0 | if (poFDefn == nullptr) |
1016 | 0 | { |
1017 | 0 | aosPath.push_back(pszKey); |
1018 | 0 | AddFieldDefn(pszAttrName, eNewType, aosPath, eNewSubType); |
1019 | 0 | } |
1020 | 0 | else |
1021 | 0 | { |
1022 | 0 | OGRUpdateFieldType(poFDefn, eNewType, eNewSubType); |
1023 | 0 | } |
1024 | 0 | } |
1025 | | |
1026 | | /************************************************************************/ |
1027 | | /* SyncToDisk() */ |
1028 | | /************************************************************************/ |
1029 | | |
1030 | | OGRErr OGRElasticLayer::SyncToDisk() |
1031 | 0 | { |
1032 | 0 | if (WriteMapIfNecessary() != OGRERR_NONE) |
1033 | 0 | return OGRERR_FAILURE; |
1034 | | |
1035 | 0 | if (!PushIndex()) |
1036 | 0 | return OGRERR_FAILURE; |
1037 | | |
1038 | 0 | return OGRERR_NONE; |
1039 | 0 | } |
1040 | | |
1041 | | /************************************************************************/ |
1042 | | /* GetLayerDefn() */ |
1043 | | /************************************************************************/ |
1044 | | |
1045 | | const OGRFeatureDefn *OGRElasticLayer::GetLayerDefn() const |
1046 | 0 | { |
1047 | |
|
1048 | 0 | const_cast<OGRElasticLayer *>(this)->FinalizeFeatureDefn(); |
1049 | |
|
1050 | 0 | return m_poFeatureDefn; |
1051 | 0 | } |
1052 | | |
1053 | | /************************************************************************/ |
1054 | | /* GetFIDColumn() */ |
1055 | | /************************************************************************/ |
1056 | | |
1057 | | const char *OGRElasticLayer::GetFIDColumn() const |
1058 | 0 | { |
1059 | 0 | GetLayerDefn(); |
1060 | 0 | return m_osFID.c_str(); |
1061 | 0 | } |
1062 | | |
1063 | | /************************************************************************/ |
1064 | | /* ResetReading() */ |
1065 | | /************************************************************************/ |
1066 | | |
1067 | | void OGRElasticLayer::ResetReading() |
1068 | 0 | { |
1069 | 0 | if (!m_osScrollID.empty()) |
1070 | 0 | { |
1071 | 0 | char **papszOptions = |
1072 | 0 | CSLAddNameValue(nullptr, "CUSTOMREQUEST", "DELETE"); |
1073 | 0 | CPLHTTPResult *psResult = m_poDS->HTTPFetch( |
1074 | 0 | (m_poDS->GetURL() + CPLString("/_search/scroll?scroll_id=") + |
1075 | 0 | m_osScrollID) |
1076 | 0 | .c_str(), |
1077 | 0 | papszOptions); |
1078 | 0 | CSLDestroy(papszOptions); |
1079 | 0 | CPLHTTPDestroyResult(psResult); |
1080 | |
|
1081 | 0 | m_osScrollID = ""; |
1082 | 0 | } |
1083 | 0 | for (int i = 0; i < (int)m_apoCachedFeatures.size(); i++) |
1084 | 0 | delete m_apoCachedFeatures[i]; |
1085 | 0 | m_apoCachedFeatures.resize(0); |
1086 | 0 | m_iCurID = 0; |
1087 | 0 | m_iCurFeatureInPage = 0; |
1088 | 0 | m_bEOF = false; |
1089 | |
|
1090 | 0 | m_nReadFeaturesSinceResetReading = 0; |
1091 | 0 | m_dfEndTimeStamp = 0; |
1092 | 0 | const double dfTimeout = m_bUseSingleQueryParams |
1093 | 0 | ? m_dfSingleQueryTimeout |
1094 | 0 | : m_dfFeatureIterationTimeout; |
1095 | 0 | if (dfTimeout > 0) |
1096 | 0 | m_dfEndTimeStamp = GetTimestamp() + dfTimeout; |
1097 | 0 | } |
1098 | | |
1099 | | /************************************************************************/ |
1100 | | /* GetNextFeature() */ |
1101 | | /************************************************************************/ |
1102 | | |
1103 | | OGRFeature *OGRElasticLayer::GetNextFeature() |
1104 | | |
1105 | 0 | { |
1106 | 0 | FinalizeFeatureDefn(); |
1107 | |
|
1108 | 0 | while (true) |
1109 | 0 | { |
1110 | 0 | OGRFeature *poFeature = GetNextRawFeature(); |
1111 | 0 | if (poFeature == nullptr) |
1112 | 0 | return nullptr; |
1113 | | |
1114 | 0 | if ((m_poFilterGeom == nullptr || |
1115 | 0 | FilterGeometry(poFeature->GetGeomFieldRef(m_iGeomFieldFilter))) && |
1116 | 0 | (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature))) |
1117 | 0 | return poFeature; |
1118 | | |
1119 | 0 | delete poFeature; |
1120 | 0 | } |
1121 | 0 | } |
1122 | | |
1123 | | /************************************************************************/ |
1124 | | /* BuildSort() */ |
1125 | | /************************************************************************/ |
1126 | | |
1127 | | json_object *OGRElasticLayer::BuildSort() |
1128 | 0 | { |
1129 | 0 | json_object *poRet = json_object_new_array(); |
1130 | 0 | for (size_t i = 0; i < m_aoSortColumns.size(); ++i) |
1131 | 0 | { |
1132 | 0 | const int nIdx = |
1133 | 0 | m_poFeatureDefn->GetFieldIndex(m_aoSortColumns[i].osColumn); |
1134 | 0 | CPLString osFieldName(nIdx == 0 |
1135 | 0 | ? CPLString("_uid") |
1136 | 0 | : BuildPathFromArray(m_aaosFieldPaths[nIdx])); |
1137 | 0 | if (CSLFindString(m_papszFieldsWithRawValue, |
1138 | 0 | m_aoSortColumns[i].osColumn) >= 0) |
1139 | 0 | { |
1140 | 0 | osFieldName += ".raw"; |
1141 | 0 | } |
1142 | 0 | json_object *poSortCol = json_object_new_object(); |
1143 | 0 | json_object *poSortProp = json_object_new_object(); |
1144 | 0 | json_object_array_add(poRet, poSortCol); |
1145 | 0 | json_object_object_add( |
1146 | 0 | poSortProp, "order", |
1147 | 0 | json_object_new_string(m_aoSortColumns[i].bAsc ? "asc" : "desc")); |
1148 | 0 | json_object_object_add(poSortCol, osFieldName, poSortProp); |
1149 | 0 | } |
1150 | 0 | return poRet; |
1151 | 0 | } |
1152 | | |
1153 | | /************************************************************************/ |
1154 | | /* BuildQuery() */ |
1155 | | /************************************************************************/ |
1156 | | |
1157 | | CPLString OGRElasticLayer::BuildQuery(bool bCountOnly) |
1158 | 0 | { |
1159 | 0 | CPLString osRet = "{ "; |
1160 | 0 | if (bCountOnly && |
1161 | 0 | (m_poDS->m_nMajorVersion < 5 || !m_osSingleQueryTimeout.empty())) |
1162 | 0 | { |
1163 | 0 | osRet += "\"size\": 0, "; |
1164 | 0 | } |
1165 | 0 | if (m_poSpatialFilter && m_poJSONFilter) |
1166 | 0 | { |
1167 | 0 | osRet += CPLSPrintf("\"query\": { \"constant_score\" : { \"filter\": " |
1168 | 0 | "{ \"bool\" : { \"must\" : [%s, %s] } } } }", |
1169 | 0 | json_object_to_json_string(m_poSpatialFilter), |
1170 | 0 | json_object_to_json_string(m_poJSONFilter)); |
1171 | 0 | } |
1172 | 0 | else |
1173 | 0 | { |
1174 | 0 | osRet += CPLSPrintf( |
1175 | 0 | "\"query\": { \"constant_score\" : { \"filter\": %s } }", |
1176 | 0 | json_object_to_json_string(m_poSpatialFilter ? m_poSpatialFilter |
1177 | 0 | : m_poJSONFilter)); |
1178 | 0 | } |
1179 | 0 | if (!bCountOnly && !m_aoSortColumns.empty()) |
1180 | 0 | { |
1181 | 0 | json_object *poSort = BuildSort(); |
1182 | 0 | osRet += |
1183 | 0 | CPLSPrintf(", \"sort\" : %s", json_object_to_json_string(poSort)); |
1184 | 0 | json_object_put(poSort); |
1185 | 0 | } |
1186 | 0 | osRet += " }"; |
1187 | 0 | return osRet; |
1188 | 0 | } |
1189 | | |
1190 | | /************************************************************************/ |
1191 | | /* GetNextRawFeature() */ |
1192 | | /************************************************************************/ |
1193 | | |
1194 | | OGRFeature *OGRElasticLayer::GetNextRawFeature() |
1195 | 0 | { |
1196 | 0 | json_object *poResponse = nullptr; |
1197 | |
|
1198 | 0 | if (m_dfEndTimeStamp > 0 && GetTimestamp() >= m_dfEndTimeStamp) |
1199 | 0 | { |
1200 | 0 | CPLDebug("ES", "Terminating request due to timeout"); |
1201 | 0 | return nullptr; |
1202 | 0 | } |
1203 | 0 | const auto nTerminateAfter = m_bUseSingleQueryParams |
1204 | 0 | ? m_nSingleQueryTerminateAfter |
1205 | 0 | : m_nFeatureIterationTerminateAfter; |
1206 | 0 | if (nTerminateAfter > 0 && |
1207 | 0 | m_nReadFeaturesSinceResetReading >= nTerminateAfter) |
1208 | 0 | { |
1209 | 0 | CPLDebug("ES", "Terminating request due to terminate_after reached"); |
1210 | 0 | return nullptr; |
1211 | 0 | } |
1212 | | |
1213 | 0 | if (m_bEOF) |
1214 | 0 | return nullptr; |
1215 | | |
1216 | 0 | if (m_iCurFeatureInPage < (int)m_apoCachedFeatures.size()) |
1217 | 0 | { |
1218 | 0 | OGRFeature *poRet = m_apoCachedFeatures[m_iCurFeatureInPage]; |
1219 | 0 | m_apoCachedFeatures[m_iCurFeatureInPage] = nullptr; |
1220 | 0 | m_iCurFeatureInPage++; |
1221 | 0 | m_nReadFeaturesSinceResetReading++; |
1222 | 0 | return poRet; |
1223 | 0 | } |
1224 | | |
1225 | 0 | for (int i = 0; i < (int)m_apoCachedFeatures.size(); i++) |
1226 | 0 | delete m_apoCachedFeatures[i]; |
1227 | 0 | m_apoCachedFeatures.resize(0); |
1228 | 0 | m_iCurFeatureInPage = 0; |
1229 | |
|
1230 | 0 | CPLString osRequest, osPostData; |
1231 | 0 | if (m_nReadFeaturesSinceResetReading == 0) |
1232 | 0 | { |
1233 | 0 | if (!m_osESSearch.empty()) |
1234 | 0 | { |
1235 | 0 | osRequest = CPLSPrintf("%s/_search?scroll=1m&size=%d", |
1236 | 0 | m_poDS->GetURL(), m_poDS->m_nBatchSize); |
1237 | 0 | osPostData = m_osESSearch; |
1238 | 0 | } |
1239 | 0 | else if ((m_poSpatialFilter && m_osJSONFilter.empty()) || |
1240 | 0 | m_poJSONFilter) |
1241 | 0 | { |
1242 | 0 | osPostData = BuildQuery(false); |
1243 | 0 | osRequest = BuildMappingURL(false); |
1244 | 0 | osRequest += |
1245 | 0 | CPLSPrintf("/_search?scroll=1m&size=%d", m_poDS->m_nBatchSize); |
1246 | 0 | } |
1247 | 0 | else if (!m_aoSortColumns.empty() && m_osJSONFilter.empty()) |
1248 | 0 | { |
1249 | 0 | osRequest = BuildMappingURL(false); |
1250 | 0 | osRequest += |
1251 | 0 | CPLSPrintf("/_search?scroll=1m&size=%d", m_poDS->m_nBatchSize); |
1252 | 0 | json_object *poSort = BuildSort(); |
1253 | 0 | osPostData = CPLSPrintf("{ \"sort\": %s }", |
1254 | 0 | json_object_to_json_string(poSort)); |
1255 | 0 | json_object_put(poSort); |
1256 | 0 | } |
1257 | 0 | else |
1258 | 0 | { |
1259 | 0 | osRequest = BuildMappingURL(false); |
1260 | 0 | osRequest += |
1261 | 0 | CPLSPrintf("/_search?scroll=1m&size=%d", m_poDS->m_nBatchSize); |
1262 | 0 | osPostData = m_osJSONFilter; |
1263 | 0 | } |
1264 | 0 | } |
1265 | 0 | else |
1266 | 0 | { |
1267 | 0 | if (m_osScrollID.empty()) |
1268 | 0 | { |
1269 | 0 | m_bEOF = true; |
1270 | 0 | return nullptr; |
1271 | 0 | } |
1272 | 0 | osRequest = CPLSPrintf("%s/_search/scroll?scroll=1m&scroll_id=%s", |
1273 | 0 | m_poDS->GetURL(), m_osScrollID.c_str()); |
1274 | 0 | } |
1275 | | |
1276 | 0 | if (m_bAddPretty) |
1277 | 0 | osRequest += "&pretty"; |
1278 | 0 | poResponse = m_poDS->RunRequest(osRequest, osPostData); |
1279 | 0 | if (poResponse == nullptr) |
1280 | 0 | { |
1281 | 0 | m_bEOF = true; |
1282 | 0 | return nullptr; |
1283 | 0 | } |
1284 | 0 | m_osScrollID.clear(); |
1285 | 0 | json_object *poScrollID = |
1286 | 0 | CPL_json_object_object_get(poResponse, "_scroll_id"); |
1287 | 0 | if (poScrollID) |
1288 | 0 | { |
1289 | 0 | const char *pszScrollID = json_object_get_string(poScrollID); |
1290 | 0 | if (pszScrollID) |
1291 | 0 | m_osScrollID = pszScrollID; |
1292 | 0 | } |
1293 | |
|
1294 | 0 | json_object *poHits = CPL_json_object_object_get(poResponse, "hits"); |
1295 | 0 | if (poHits == nullptr || json_object_get_type(poHits) != json_type_object) |
1296 | 0 | { |
1297 | 0 | m_bEOF = true; |
1298 | 0 | json_object_put(poResponse); |
1299 | 0 | return nullptr; |
1300 | 0 | } |
1301 | 0 | poHits = CPL_json_object_object_get(poHits, "hits"); |
1302 | 0 | if (poHits == nullptr || json_object_get_type(poHits) != json_type_array) |
1303 | 0 | { |
1304 | 0 | m_bEOF = true; |
1305 | 0 | json_object_put(poResponse); |
1306 | 0 | return nullptr; |
1307 | 0 | } |
1308 | 0 | const auto nHits = json_object_array_length(poHits); |
1309 | 0 | if (nHits == 0) |
1310 | 0 | { |
1311 | 0 | m_osScrollID = ""; |
1312 | 0 | m_bEOF = true; |
1313 | 0 | json_object_put(poResponse); |
1314 | 0 | return nullptr; |
1315 | 0 | } |
1316 | 0 | for (auto i = decltype(nHits){0}; i < nHits; i++) |
1317 | 0 | { |
1318 | 0 | json_object *poHit = json_object_array_get_idx(poHits, i); |
1319 | 0 | if (poHit == nullptr || json_object_get_type(poHit) != json_type_object) |
1320 | 0 | { |
1321 | 0 | continue; |
1322 | 0 | } |
1323 | 0 | json_object *poSource = CPL_json_object_object_get(poHit, "_source"); |
1324 | 0 | if (poSource == nullptr || |
1325 | 0 | json_object_get_type(poSource) != json_type_object) |
1326 | 0 | { |
1327 | 0 | continue; |
1328 | 0 | } |
1329 | | |
1330 | 0 | const char *pszId = nullptr; |
1331 | 0 | json_object *poId = CPL_json_object_object_get(poHit, "_id"); |
1332 | 0 | if (poId != nullptr && json_object_get_type(poId) == json_type_string) |
1333 | 0 | pszId = json_object_get_string(poId); |
1334 | |
|
1335 | 0 | OGRFeature *poFeature = new OGRFeature(m_poFeatureDefn); |
1336 | 0 | if (pszId) |
1337 | 0 | poFeature->SetField("_id", pszId); |
1338 | |
|
1339 | 0 | if (m_bAddSourceIndexName) |
1340 | 0 | { |
1341 | 0 | json_object *poIndex = CPL_json_object_object_get(poHit, "_index"); |
1342 | 0 | if (poId != nullptr && |
1343 | 0 | json_object_get_type(poId) == json_type_string) |
1344 | 0 | poFeature->SetField("_index", json_object_get_string(poIndex)); |
1345 | 0 | } |
1346 | |
|
1347 | 0 | if (!m_osESSearch.empty()) |
1348 | 0 | { |
1349 | 0 | json_object *poIndex = CPL_json_object_object_get(poHit, "_index"); |
1350 | 0 | if (poIndex != nullptr && |
1351 | 0 | json_object_get_type(poIndex) == json_type_string) |
1352 | 0 | poFeature->SetField("_index", json_object_get_string(poIndex)); |
1353 | |
|
1354 | 0 | json_object *poType = CPL_json_object_object_get(poHit, "_type"); |
1355 | 0 | if (poType != nullptr && |
1356 | 0 | json_object_get_type(poType) == json_type_string) |
1357 | 0 | poFeature->SetField("_type", json_object_get_string(poType)); |
1358 | 0 | } |
1359 | |
|
1360 | 0 | if (m_poDS->m_bJSonField) |
1361 | 0 | poFeature->SetField("_json", json_object_to_json_string(poSource)); |
1362 | |
|
1363 | 0 | BuildFeature(poFeature, poSource, CPLString()); |
1364 | 0 | if (poFeature->GetFID() < 0) |
1365 | 0 | poFeature->SetFID(++m_iCurID); |
1366 | 0 | m_apoCachedFeatures.push_back(poFeature); |
1367 | 0 | } |
1368 | |
|
1369 | 0 | json_object_put(poResponse); |
1370 | 0 | if (!m_apoCachedFeatures.empty()) |
1371 | 0 | { |
1372 | 0 | OGRFeature *poRet = m_apoCachedFeatures[0]; |
1373 | 0 | m_apoCachedFeatures[0] = nullptr; |
1374 | 0 | m_iCurFeatureInPage++; |
1375 | 0 | m_nReadFeaturesSinceResetReading++; |
1376 | 0 | return poRet; |
1377 | 0 | } |
1378 | 0 | return nullptr; |
1379 | 0 | } |
1380 | | |
1381 | | /************************************************************************/ |
1382 | | /* decode_geohash_bbox() */ |
1383 | | /************************************************************************/ |
1384 | | |
1385 | | /* Derived from routine from |
1386 | | * https://github.com/davetroy/geohash/blob/master/ext/geohash_native.c */ |
1387 | | /* (c) 2008-2010 David Troy, davetroy@gmail.com, (The MIT License) */ |
1388 | | |
1389 | | static const char BASE32[] = "0123456789bcdefghjkmnpqrstuvwxyz"; |
1390 | | |
1391 | | static void decode_geohash_bbox(const char *geohash, double lat[2], |
1392 | | double lon[2]) |
1393 | 0 | { |
1394 | 0 | int i; |
1395 | 0 | int j; |
1396 | 0 | int hashlen; |
1397 | 0 | char c; |
1398 | 0 | char cd; |
1399 | 0 | char mask; |
1400 | 0 | char is_even = 1; |
1401 | 0 | static const char bits[] = {16, 8, 4, 2, 1}; |
1402 | 0 | lat[0] = -90.0; |
1403 | 0 | lat[1] = 90.0; |
1404 | 0 | lon[0] = -180.0; |
1405 | 0 | lon[1] = 180.0; |
1406 | 0 | hashlen = static_cast<int>(strlen(geohash)); |
1407 | 0 | for (i = 0; i < hashlen; i++) |
1408 | 0 | { |
1409 | 0 | c = static_cast<char>( |
1410 | 0 | CPLTolower(static_cast<unsigned char>(geohash[i]))); |
1411 | 0 | cd = static_cast<char>(strchr(BASE32, c) - BASE32); |
1412 | 0 | for (j = 0; j < 5; j++) |
1413 | 0 | { |
1414 | 0 | mask = bits[j]; |
1415 | 0 | if (is_even) |
1416 | 0 | { |
1417 | 0 | lon[!(cd & mask)] = (lon[0] + lon[1]) / 2; |
1418 | 0 | } |
1419 | 0 | else |
1420 | 0 | { |
1421 | 0 | lat[!(cd & mask)] = (lat[0] + lat[1]) / 2; |
1422 | 0 | } |
1423 | 0 | is_even = !is_even; |
1424 | 0 | } |
1425 | 0 | } |
1426 | 0 | } |
1427 | | |
1428 | | /************************************************************************/ |
1429 | | /* BuildFeature() */ |
1430 | | /************************************************************************/ |
1431 | | |
1432 | | void OGRElasticLayer::BuildFeature(OGRFeature *poFeature, json_object *poSource, |
1433 | | CPLString osPath) |
1434 | 0 | { |
1435 | 0 | json_object_iter it; |
1436 | 0 | it.key = nullptr; |
1437 | 0 | it.val = nullptr; |
1438 | 0 | it.entry = nullptr; |
1439 | 0 | CPLString osCurPath; |
1440 | 0 | json_object_object_foreachC(poSource, it) |
1441 | 0 | { |
1442 | 0 | if (osPath.empty() && !m_osFID.empty() && EQUAL(m_osFID, it.key)) |
1443 | 0 | { |
1444 | 0 | json_type eJSONType = json_object_get_type(it.val); |
1445 | 0 | if (eJSONType == json_type_int) |
1446 | 0 | { |
1447 | 0 | poFeature->SetFID((GIntBig)json_object_get_int64(it.val)); |
1448 | 0 | continue; |
1449 | 0 | } |
1450 | 0 | } |
1451 | | |
1452 | 0 | if (!osPath.empty()) |
1453 | 0 | osCurPath = osPath + "." + it.key; |
1454 | 0 | else |
1455 | 0 | osCurPath = it.key; |
1456 | 0 | std::map<CPLString, int>::iterator oIter = |
1457 | 0 | m_aosMapToFieldIndex.find(osCurPath); |
1458 | 0 | if (oIter != m_aosMapToFieldIndex.end()) |
1459 | 0 | { |
1460 | 0 | switch (json_object_get_type(it.val)) |
1461 | 0 | { |
1462 | 0 | case json_type_null: |
1463 | 0 | poFeature->SetFieldNull(oIter->second); |
1464 | 0 | break; |
1465 | 0 | case json_type_boolean: |
1466 | 0 | poFeature->SetField(oIter->second, |
1467 | 0 | json_object_get_boolean(it.val)); |
1468 | 0 | break; |
1469 | 0 | case json_type_int: |
1470 | 0 | poFeature->SetField(oIter->second, |
1471 | 0 | (GIntBig)json_object_get_int64(it.val)); |
1472 | 0 | break; |
1473 | 0 | case json_type_double: |
1474 | 0 | poFeature->SetField(oIter->second, |
1475 | 0 | json_object_get_double(it.val)); |
1476 | 0 | break; |
1477 | 0 | case json_type_array: |
1478 | 0 | { |
1479 | 0 | if (m_poFeatureDefn->GetFieldDefn(oIter->second) |
1480 | 0 | ->GetType() == OFTIntegerList) |
1481 | 0 | { |
1482 | 0 | std::vector<int> anValues; |
1483 | 0 | const auto nLength = json_object_array_length(it.val); |
1484 | 0 | for (auto i = decltype(nLength){0}; i < nLength; i++) |
1485 | 0 | { |
1486 | 0 | anValues.push_back(json_object_get_int( |
1487 | 0 | json_object_array_get_idx(it.val, i))); |
1488 | 0 | } |
1489 | 0 | if (nLength) |
1490 | 0 | poFeature->SetField(oIter->second, |
1491 | 0 | static_cast<int>(nLength), |
1492 | 0 | &anValues[0]); |
1493 | 0 | } |
1494 | 0 | else if (m_poFeatureDefn->GetFieldDefn(oIter->second) |
1495 | 0 | ->GetType() == OFTInteger64List) |
1496 | 0 | { |
1497 | 0 | std::vector<GIntBig> anValues; |
1498 | 0 | const auto nLength = json_object_array_length(it.val); |
1499 | 0 | for (auto i = decltype(nLength){0}; i < nLength; i++) |
1500 | 0 | { |
1501 | 0 | anValues.push_back(json_object_get_int64( |
1502 | 0 | json_object_array_get_idx(it.val, i))); |
1503 | 0 | } |
1504 | 0 | if (nLength) |
1505 | 0 | poFeature->SetField(oIter->second, |
1506 | 0 | static_cast<int>(nLength), |
1507 | 0 | &anValues[0]); |
1508 | 0 | } |
1509 | 0 | else if (m_poFeatureDefn->GetFieldDefn(oIter->second) |
1510 | 0 | ->GetType() == OFTRealList) |
1511 | 0 | { |
1512 | 0 | std::vector<double> adfValues; |
1513 | 0 | const auto nLength = json_object_array_length(it.val); |
1514 | 0 | for (auto i = decltype(nLength){0}; i < nLength; i++) |
1515 | 0 | { |
1516 | 0 | adfValues.push_back(json_object_get_double( |
1517 | 0 | json_object_array_get_idx(it.val, i))); |
1518 | 0 | } |
1519 | 0 | if (nLength) |
1520 | 0 | poFeature->SetField(oIter->second, |
1521 | 0 | static_cast<int>(nLength), |
1522 | 0 | &adfValues[0]); |
1523 | 0 | } |
1524 | 0 | else if (m_poFeatureDefn->GetFieldDefn(oIter->second) |
1525 | 0 | ->GetType() == OFTStringList) |
1526 | 0 | { |
1527 | 0 | std::vector<char *> apszValues; |
1528 | 0 | const auto nLength = json_object_array_length(it.val); |
1529 | 0 | for (auto i = decltype(nLength){0}; i < nLength; i++) |
1530 | 0 | { |
1531 | 0 | apszValues.push_back( |
1532 | 0 | CPLStrdup(json_object_get_string( |
1533 | 0 | json_object_array_get_idx(it.val, i)))); |
1534 | 0 | } |
1535 | 0 | apszValues.push_back(nullptr); |
1536 | 0 | poFeature->SetField(oIter->second, &apszValues[0]); |
1537 | 0 | for (auto i = decltype(nLength){0}; i < nLength; i++) |
1538 | 0 | { |
1539 | 0 | CPLFree(apszValues[i]); |
1540 | 0 | } |
1541 | 0 | } |
1542 | 0 | break; |
1543 | 0 | } |
1544 | 0 | default: |
1545 | 0 | { |
1546 | 0 | if (m_poFeatureDefn->GetFieldDefn(oIter->second) |
1547 | 0 | ->GetType() == OFTBinary) |
1548 | 0 | { |
1549 | 0 | GByte *pabyBase64 = |
1550 | 0 | (GByte *)CPLStrdup(json_object_get_string(it.val)); |
1551 | 0 | int nBytes = CPLBase64DecodeInPlace(pabyBase64); |
1552 | 0 | poFeature->SetField(oIter->second, nBytes, pabyBase64); |
1553 | 0 | CPLFree(pabyBase64); |
1554 | 0 | } |
1555 | 0 | else |
1556 | 0 | { |
1557 | 0 | poFeature->SetField(oIter->second, |
1558 | 0 | json_object_get_string(it.val)); |
1559 | 0 | } |
1560 | 0 | break; |
1561 | 0 | } |
1562 | 0 | } |
1563 | 0 | } |
1564 | 0 | else if ((oIter = m_aosMapToGeomFieldIndex.find(osCurPath)) != |
1565 | 0 | m_aosMapToGeomFieldIndex.end()) |
1566 | 0 | { |
1567 | 0 | const auto poSRS = m_poFeatureDefn->GetGeomFieldDefn(oIter->second) |
1568 | 0 | ->GetSpatialRef(); |
1569 | 0 | OGRGeometry *poGeom = nullptr; |
1570 | 0 | if (m_abIsGeoPoint[oIter->second]) |
1571 | 0 | { |
1572 | 0 | json_type eJSONType = json_object_get_type(it.val); |
1573 | 0 | if (eJSONType == json_type_array && |
1574 | 0 | json_object_array_length(it.val) == 2) |
1575 | 0 | { |
1576 | 0 | json_object *poX = json_object_array_get_idx(it.val, 0); |
1577 | 0 | json_object *poY = json_object_array_get_idx(it.val, 1); |
1578 | 0 | if (poX != nullptr && poY != nullptr) |
1579 | 0 | { |
1580 | 0 | poGeom = new OGRPoint(json_object_get_double(poX), |
1581 | 0 | json_object_get_double(poY)); |
1582 | 0 | } |
1583 | 0 | } |
1584 | 0 | else if (eJSONType == json_type_object) |
1585 | 0 | { |
1586 | 0 | json_object *poX = |
1587 | 0 | CPL_json_object_object_get(it.val, "lon"); |
1588 | 0 | json_object *poY = |
1589 | 0 | CPL_json_object_object_get(it.val, "lat"); |
1590 | 0 | if (poX != nullptr && poY != nullptr) |
1591 | 0 | { |
1592 | 0 | poGeom = new OGRPoint(json_object_get_double(poX), |
1593 | 0 | json_object_get_double(poY)); |
1594 | 0 | } |
1595 | 0 | } |
1596 | 0 | else if (eJSONType == json_type_string) |
1597 | 0 | { |
1598 | 0 | const char *pszLatLon = json_object_get_string(it.val); |
1599 | 0 | char **papszTokens = CSLTokenizeString2(pszLatLon, ",", 0); |
1600 | 0 | if (CSLCount(papszTokens) == 2) |
1601 | 0 | { |
1602 | 0 | poGeom = new OGRPoint(CPLAtof(papszTokens[1]), |
1603 | 0 | CPLAtof(papszTokens[0])); |
1604 | 0 | } |
1605 | 0 | else |
1606 | 0 | { |
1607 | 0 | double lat[2] = {0.0, 0.0}; |
1608 | 0 | double lon[2] = {0.0, 0.0}; |
1609 | 0 | decode_geohash_bbox(pszLatLon, lat, lon); |
1610 | 0 | poGeom = new OGRPoint((lon[0] + lon[1]) / 2, |
1611 | 0 | (lat[0] + lat[1]) / 2); |
1612 | 0 | } |
1613 | |
|
1614 | 0 | CSLDestroy(papszTokens); |
1615 | 0 | } |
1616 | 0 | } |
1617 | 0 | else if (json_object_get_type(it.val) == json_type_object) |
1618 | 0 | { |
1619 | 0 | json_object *poType = |
1620 | 0 | CPL_json_object_object_get(it.val, "type"); |
1621 | 0 | json_object *poRadius = |
1622 | 0 | CPL_json_object_object_get(it.val, "radius"); |
1623 | 0 | json_object *poCoordinates = |
1624 | 0 | CPL_json_object_object_get(it.val, "coordinates"); |
1625 | 0 | if (poType && poRadius && poCoordinates && |
1626 | 0 | json_object_get_type(poType) == json_type_string && |
1627 | 0 | EQUAL(json_object_get_string(poType), "circle") && |
1628 | 0 | (json_object_get_type(poRadius) == json_type_string || |
1629 | 0 | json_object_get_type(poRadius) == json_type_double || |
1630 | 0 | json_object_get_type(poRadius) == json_type_int) && |
1631 | 0 | json_object_get_type(poCoordinates) == json_type_array && |
1632 | 0 | json_object_array_length(poCoordinates) == 2) |
1633 | 0 | { |
1634 | 0 | const char *pszRadius = json_object_get_string(poRadius); |
1635 | 0 | const double dfX = json_object_get_double( |
1636 | 0 | json_object_array_get_idx(poCoordinates, 0)); |
1637 | 0 | const double dfY = json_object_get_double( |
1638 | 0 | json_object_array_get_idx(poCoordinates, 1)); |
1639 | 0 | const int nRadiusLength = (int)strlen(pszRadius); |
1640 | 0 | double dfRadius = CPLAtof(pszRadius); |
1641 | 0 | double dfUnit = 0.0; |
1642 | 0 | if (nRadiusLength >= 1 && |
1643 | 0 | pszRadius[nRadiusLength - 1] == 'm') |
1644 | 0 | { |
1645 | 0 | if (nRadiusLength >= 2 && |
1646 | 0 | pszRadius[nRadiusLength - 2] == 'k') |
1647 | 0 | dfUnit = 1000; |
1648 | 0 | else if (nRadiusLength >= 2 && |
1649 | 0 | pszRadius[nRadiusLength - 2] >= '0' && |
1650 | 0 | pszRadius[nRadiusLength - 2] <= '9') |
1651 | 0 | dfUnit = 1; |
1652 | 0 | } |
1653 | 0 | else if (nRadiusLength >= 1 && |
1654 | 0 | pszRadius[nRadiusLength - 1] >= '0' && |
1655 | 0 | pszRadius[nRadiusLength - 1] <= '9') |
1656 | 0 | { |
1657 | 0 | dfUnit = 1; |
1658 | 0 | } |
1659 | |
|
1660 | 0 | if (dfRadius == 0) |
1661 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
1662 | 0 | "Unknown unit in %s", pszRadius); |
1663 | 0 | else |
1664 | 0 | { |
1665 | 0 | dfRadius *= dfUnit; |
1666 | 0 | OGRLinearRing *poRing = new OGRLinearRing(); |
1667 | 0 | double dfSemiMajor = OGR_GREATCIRCLE_DEFAULT_RADIUS; |
1668 | 0 | if (poSRS && poSRS->IsGeographic()) |
1669 | 0 | dfSemiMajor = poSRS->GetSemiMajor(); |
1670 | 0 | for (double dfStep = 0; dfStep <= 360; dfStep += 4) |
1671 | 0 | { |
1672 | 0 | double dfLat = 0.0; |
1673 | 0 | double dfLon = 0.0; |
1674 | 0 | OGR_GreatCircle_ExtendPosition(dfY, dfX, dfRadius, |
1675 | 0 | dfSemiMajor, dfStep, |
1676 | 0 | &dfLat, &dfLon); |
1677 | 0 | poRing->addPoint(dfLon, dfLat); |
1678 | 0 | } |
1679 | 0 | OGRPolygon *poPoly = new OGRPolygon(); |
1680 | 0 | poPoly->addRingDirectly(poRing); |
1681 | 0 | poGeom = poPoly; |
1682 | 0 | } |
1683 | 0 | } |
1684 | 0 | else if (poType && poCoordinates && |
1685 | 0 | json_object_get_type(poType) == json_type_string && |
1686 | 0 | EQUAL(json_object_get_string(poType), "envelope") && |
1687 | 0 | json_object_get_type(poCoordinates) == |
1688 | 0 | json_type_array && |
1689 | 0 | json_object_array_length(poCoordinates) == 2) |
1690 | 0 | { |
1691 | 0 | json_object *poCorner1 = |
1692 | 0 | json_object_array_get_idx(poCoordinates, 0); |
1693 | 0 | json_object *poCorner2 = |
1694 | 0 | json_object_array_get_idx(poCoordinates, 1); |
1695 | 0 | if (poCorner1 && poCorner2 && |
1696 | 0 | json_object_get_type(poCorner1) == json_type_array && |
1697 | 0 | json_object_array_length(poCorner1) == 2 && |
1698 | 0 | json_object_get_type(poCorner2) == json_type_array && |
1699 | 0 | json_object_array_length(poCorner2) == 2) |
1700 | 0 | { |
1701 | 0 | const double dfX1 = json_object_get_double( |
1702 | 0 | json_object_array_get_idx(poCorner1, 0)); |
1703 | 0 | const double dfY1 = json_object_get_double( |
1704 | 0 | json_object_array_get_idx(poCorner1, 1)); |
1705 | 0 | const double dfX2 = json_object_get_double( |
1706 | 0 | json_object_array_get_idx(poCorner2, 0)); |
1707 | 0 | const double dfY2 = json_object_get_double( |
1708 | 0 | json_object_array_get_idx(poCorner2, 1)); |
1709 | 0 | OGRLinearRing *poRing = new OGRLinearRing(); |
1710 | 0 | poRing->addPoint(dfX1, dfY1); |
1711 | 0 | poRing->addPoint(dfX2, dfY1); |
1712 | 0 | poRing->addPoint(dfX2, dfY2); |
1713 | 0 | poRing->addPoint(dfX1, dfY2); |
1714 | 0 | poRing->addPoint(dfX1, dfY1); |
1715 | 0 | OGRPolygon *poPoly = new OGRPolygon(); |
1716 | 0 | poPoly->addRingDirectly(poRing); |
1717 | 0 | poGeom = poPoly; |
1718 | 0 | } |
1719 | 0 | } |
1720 | 0 | else |
1721 | 0 | { |
1722 | 0 | poGeom = OGRGeoJSONReadGeometry( |
1723 | 0 | it.val, /* bHasM = */ false, |
1724 | 0 | /* OGRSpatialReference* = */ nullptr) |
1725 | 0 | .release(); |
1726 | 0 | } |
1727 | 0 | } |
1728 | 0 | else if (json_object_get_type(it.val) == json_type_string) |
1729 | 0 | { |
1730 | | // Assume this is WKT |
1731 | 0 | OGRGeometryFactory::createFromWkt( |
1732 | 0 | json_object_get_string(it.val), nullptr, &poGeom); |
1733 | 0 | } |
1734 | |
|
1735 | 0 | if (poGeom != nullptr) |
1736 | 0 | { |
1737 | 0 | poGeom->assignSpatialReference(poSRS); |
1738 | 0 | poFeature->SetGeomFieldDirectly(oIter->second, poGeom); |
1739 | 0 | } |
1740 | 0 | } |
1741 | 0 | else if (json_object_get_type(it.val) == json_type_object && |
1742 | 0 | (m_poDS->m_bFlattenNestedAttributes || |
1743 | 0 | (osPath.empty() && m_osMappingName == "FeatureCollection" && |
1744 | 0 | strcmp(it.key, "properties") == 0))) |
1745 | 0 | { |
1746 | 0 | BuildFeature(poFeature, it.val, osCurPath); |
1747 | 0 | } |
1748 | 0 | else if (json_object_get_type(it.val) == json_type_object && |
1749 | 0 | !m_poDS->m_bFlattenNestedAttributes) |
1750 | 0 | { |
1751 | 0 | if (m_aosMapToGeomFieldIndex.find(osCurPath + ".coordinates") != |
1752 | 0 | m_aosMapToGeomFieldIndex.end()) |
1753 | 0 | { |
1754 | 0 | BuildFeature(poFeature, it.val, osCurPath); |
1755 | 0 | } |
1756 | 0 | } |
1757 | 0 | } |
1758 | 0 | } |
1759 | | |
1760 | | /************************************************************************/ |
1761 | | /* AppendGroup() */ |
1762 | | /************************************************************************/ |
1763 | | |
1764 | | static json_object *AppendGroup(json_object *parent, const CPLString &name) |
1765 | 0 | { |
1766 | 0 | json_object *obj = json_object_new_object(); |
1767 | 0 | json_object *properties = json_object_new_object(); |
1768 | 0 | json_object_object_add(parent, name, obj); |
1769 | 0 | json_object_object_add(obj, "properties", properties); |
1770 | 0 | return properties; |
1771 | 0 | } |
1772 | | |
1773 | | /************************************************************************/ |
1774 | | /* AddPropertyMap() */ |
1775 | | /************************************************************************/ |
1776 | | |
1777 | | static json_object *AddPropertyMap(const CPLString &type) |
1778 | 0 | { |
1779 | 0 | json_object *obj = json_object_new_object(); |
1780 | 0 | json_object_object_add(obj, "type", json_object_new_string(type.c_str())); |
1781 | 0 | return obj; |
1782 | 0 | } |
1783 | | |
1784 | | /************************************************************************/ |
1785 | | /* GetContainerForMapping() */ |
1786 | | /************************************************************************/ |
1787 | | |
1788 | | static json_object * |
1789 | | GetContainerForMapping(json_object *poContainer, |
1790 | | const std::vector<CPLString> &aosPath, |
1791 | | std::map<std::vector<CPLString>, json_object *> &oMap) |
1792 | 0 | { |
1793 | 0 | std::vector<CPLString> aosSubPath; |
1794 | 0 | for (int j = 0; j < (int)aosPath.size() - 1; j++) |
1795 | 0 | { |
1796 | 0 | aosSubPath.push_back(aosPath[j]); |
1797 | 0 | std::map<std::vector<CPLString>, json_object *>::iterator oIter = |
1798 | 0 | oMap.find(aosSubPath); |
1799 | 0 | if (oIter == oMap.end()) |
1800 | 0 | { |
1801 | 0 | json_object *poNewContainer = json_object_new_object(); |
1802 | 0 | json_object *poProperties = json_object_new_object(); |
1803 | 0 | json_object_object_add(poContainer, aosPath[j], poNewContainer); |
1804 | 0 | json_object_object_add(poNewContainer, "properties", poProperties); |
1805 | 0 | oMap[aosSubPath] = poProperties; |
1806 | 0 | poContainer = poProperties; |
1807 | 0 | } |
1808 | 0 | else |
1809 | 0 | { |
1810 | 0 | poContainer = oIter->second; |
1811 | 0 | } |
1812 | 0 | } |
1813 | 0 | return poContainer; |
1814 | 0 | } |
1815 | | |
1816 | | /************************************************************************/ |
1817 | | /* BuildMap() */ |
1818 | | /************************************************************************/ |
1819 | | |
1820 | | CPLString OGRElasticLayer::BuildMap() |
1821 | 0 | { |
1822 | 0 | json_object *map = json_object_new_object(); |
1823 | |
|
1824 | 0 | std::map<std::vector<CPLString>, json_object *> oMap; |
1825 | |
|
1826 | 0 | json_object *poMapping; |
1827 | 0 | json_object *poMappingProperties = json_object_new_object(); |
1828 | 0 | if (m_poDS->m_nMajorVersion < 7) |
1829 | 0 | { |
1830 | 0 | poMapping = json_object_new_object(); |
1831 | 0 | json_object_object_add(map, m_osMappingName, poMapping); |
1832 | 0 | } |
1833 | 0 | else |
1834 | 0 | { |
1835 | 0 | poMapping = map; |
1836 | 0 | } |
1837 | 0 | json_object_object_add(poMapping, "properties", poMappingProperties); |
1838 | |
|
1839 | 0 | if (m_poDS->m_nMajorVersion < 7 && m_osMappingName == "FeatureCollection") |
1840 | 0 | { |
1841 | 0 | json_object_object_add( |
1842 | 0 | poMappingProperties, "type", |
1843 | 0 | AddPropertyMap(m_poDS->m_nMajorVersion >= 5 ? "text" : "string")); |
1844 | |
|
1845 | 0 | std::vector<CPLString> aosPath; |
1846 | 0 | aosPath.push_back("properties"); |
1847 | 0 | aosPath.push_back("dummy"); |
1848 | 0 | GetContainerForMapping(poMappingProperties, aosPath, oMap); |
1849 | 0 | } |
1850 | | |
1851 | | /* skip _id field */ |
1852 | 0 | for (int i = 1; i < m_poFeatureDefn->GetFieldCount(); i++) |
1853 | 0 | { |
1854 | 0 | OGRFieldDefn *poFieldDefn = m_poFeatureDefn->GetFieldDefn(i); |
1855 | |
|
1856 | 0 | json_object *poContainer = GetContainerForMapping( |
1857 | 0 | poMappingProperties, m_aaosFieldPaths[i], oMap); |
1858 | 0 | const char *pszLastComponent = m_aaosFieldPaths[i].back(); |
1859 | |
|
1860 | 0 | const char *pszType = "string"; |
1861 | 0 | const char *pszFormat = nullptr; |
1862 | |
|
1863 | 0 | switch (poFieldDefn->GetType()) |
1864 | 0 | { |
1865 | 0 | case OFTInteger: |
1866 | 0 | case OFTIntegerList: |
1867 | 0 | { |
1868 | 0 | if (poFieldDefn->GetSubType() == OFSTBoolean) |
1869 | 0 | pszType = "boolean"; |
1870 | 0 | else |
1871 | 0 | pszType = "integer"; |
1872 | 0 | break; |
1873 | 0 | } |
1874 | 0 | case OFTInteger64: |
1875 | 0 | case OFTInteger64List: |
1876 | 0 | pszType = "long"; |
1877 | 0 | break; |
1878 | 0 | case OFTReal: |
1879 | 0 | case OFTRealList: |
1880 | 0 | pszType = "double"; |
1881 | 0 | break; |
1882 | 0 | case OFTDateTime: |
1883 | 0 | case OFTDate: |
1884 | 0 | pszType = "date"; |
1885 | 0 | pszFormat = "yyyy/MM/dd HH:mm:ss.SSSZZ||yyyy/MM/dd " |
1886 | 0 | "HH:mm:ss.SSS||yyyy/MM/dd"; |
1887 | 0 | break; |
1888 | 0 | case OFTTime: |
1889 | 0 | pszType = "date"; |
1890 | 0 | pszFormat = "HH:mm:ss.SSS"; |
1891 | 0 | break; |
1892 | 0 | case OFTBinary: |
1893 | 0 | pszType = "binary"; |
1894 | 0 | break; |
1895 | 0 | default: |
1896 | 0 | break; |
1897 | 0 | } |
1898 | | |
1899 | 0 | bool bAnalyzed = EQUAL(pszType, "string"); |
1900 | 0 | json_object *poPropertyMap = json_object_new_object(); |
1901 | 0 | if (m_poDS->m_nMajorVersion >= 5 && EQUAL(pszType, "string")) |
1902 | 0 | { |
1903 | 0 | if (CSLFindString(m_papszNotAnalyzedFields, |
1904 | 0 | poFieldDefn->GetNameRef()) >= 0 || |
1905 | 0 | (CSLCount(m_papszNotAnalyzedFields) == 1 && |
1906 | 0 | EQUAL(m_papszNotAnalyzedFields[0], "{ALL}"))) |
1907 | 0 | { |
1908 | 0 | bAnalyzed = false; |
1909 | 0 | pszType = "keyword"; |
1910 | 0 | } |
1911 | 0 | else |
1912 | 0 | pszType = "text"; |
1913 | 0 | } |
1914 | 0 | json_object_object_add(poPropertyMap, "type", |
1915 | 0 | json_object_new_string(pszType)); |
1916 | 0 | if (pszFormat) |
1917 | 0 | json_object_object_add(poPropertyMap, "format", |
1918 | 0 | json_object_new_string(pszFormat)); |
1919 | 0 | if (m_bStoreFields || |
1920 | 0 | CSLFindString(m_papszStoredFields, poFieldDefn->GetNameRef()) >= 0) |
1921 | 0 | json_object_object_add(poPropertyMap, "store", |
1922 | 0 | json_object_new_string("yes")); |
1923 | 0 | if (m_poDS->m_nMajorVersion < 5 && |
1924 | 0 | (CSLFindString(m_papszNotAnalyzedFields, |
1925 | 0 | poFieldDefn->GetNameRef()) >= 0 || |
1926 | 0 | (CSLCount(m_papszNotAnalyzedFields) == 1 && |
1927 | 0 | EQUAL(m_papszNotAnalyzedFields[0], "{ALL}")))) |
1928 | 0 | { |
1929 | 0 | bAnalyzed = false; |
1930 | 0 | json_object_object_add(poPropertyMap, "index", |
1931 | 0 | json_object_new_string("not_analyzed")); |
1932 | 0 | } |
1933 | 0 | else if (CSLFindString(m_papszNotIndexedFields, |
1934 | 0 | poFieldDefn->GetNameRef()) >= 0) |
1935 | 0 | json_object_object_add(poPropertyMap, "index", |
1936 | 0 | json_object_new_string("no")); |
1937 | |
|
1938 | 0 | if (bAnalyzed && (CSLFindString(m_papszFieldsWithRawValue, |
1939 | 0 | poFieldDefn->GetNameRef()) >= 0 || |
1940 | 0 | (CSLCount(m_papszFieldsWithRawValue) == 1 && |
1941 | 0 | EQUAL(m_papszFieldsWithRawValue[0], "{ALL}")))) |
1942 | 0 | { |
1943 | 0 | json_object *poFields = json_object_new_object(); |
1944 | 0 | json_object *poRaw = json_object_new_object(); |
1945 | 0 | json_object_object_add(poFields, "raw", poRaw); |
1946 | 0 | if (m_poDS->m_nMajorVersion >= 5) |
1947 | 0 | { |
1948 | 0 | json_object_object_add(poRaw, "type", |
1949 | 0 | json_object_new_string("keyword")); |
1950 | 0 | } |
1951 | 0 | else |
1952 | 0 | { |
1953 | 0 | json_object_object_add(poRaw, "type", |
1954 | 0 | json_object_new_string("string")); |
1955 | 0 | json_object_object_add(poRaw, "index", |
1956 | 0 | json_object_new_string("not_analyzed")); |
1957 | 0 | } |
1958 | 0 | json_object_object_add(poPropertyMap, "fields", poFields); |
1959 | 0 | } |
1960 | |
|
1961 | 0 | json_object_object_add(poContainer, pszLastComponent, poPropertyMap); |
1962 | 0 | } |
1963 | | |
1964 | 0 | for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); i++) |
1965 | 0 | { |
1966 | 0 | std::vector<CPLString> aosPath = m_aaosGeomFieldPaths[i]; |
1967 | 0 | bool bAddGeoJSONType = false; |
1968 | 0 | if (m_abIsGeoPoint[i] && aosPath.size() >= 2 && |
1969 | 0 | aosPath.back() == "coordinates") |
1970 | 0 | { |
1971 | 0 | bAddGeoJSONType = true; |
1972 | 0 | aosPath.resize((int)aosPath.size() - 1); |
1973 | 0 | } |
1974 | |
|
1975 | 0 | json_object *poContainer = |
1976 | 0 | GetContainerForMapping(poMappingProperties, aosPath, oMap); |
1977 | 0 | const char *pszLastComponent = aosPath.back(); |
1978 | |
|
1979 | 0 | if (m_abIsGeoPoint[i]) |
1980 | 0 | { |
1981 | 0 | json_object *geo_point = AddPropertyMap("geo_point"); |
1982 | 0 | if (bAddGeoJSONType) |
1983 | 0 | { |
1984 | 0 | json_object *geometry = |
1985 | 0 | AppendGroup(poContainer, pszLastComponent); |
1986 | 0 | json_object_object_add( |
1987 | 0 | geometry, "type", |
1988 | 0 | AddPropertyMap(m_poDS->m_nMajorVersion >= 5 ? "text" |
1989 | 0 | : "string")); |
1990 | 0 | json_object_object_add(geometry, "coordinates", geo_point); |
1991 | 0 | } |
1992 | 0 | else |
1993 | 0 | { |
1994 | 0 | json_object_object_add(poContainer, pszLastComponent, |
1995 | 0 | geo_point); |
1996 | 0 | } |
1997 | 0 | if (!m_osPrecision.empty()) |
1998 | 0 | { |
1999 | 0 | json_object *field_data = json_object_new_object(); |
2000 | 0 | json_object_object_add(geo_point, "fielddata", field_data); |
2001 | 0 | json_object_object_add(field_data, "format", |
2002 | 0 | json_object_new_string("compressed")); |
2003 | 0 | json_object_object_add( |
2004 | 0 | field_data, "precision", |
2005 | 0 | json_object_new_string(m_osPrecision.c_str())); |
2006 | 0 | } |
2007 | 0 | } |
2008 | 0 | else |
2009 | 0 | { |
2010 | 0 | json_object *geometry = json_object_new_object(); |
2011 | 0 | json_object_object_add(poContainer, pszLastComponent, geometry); |
2012 | 0 | json_object_object_add(geometry, "type", |
2013 | 0 | json_object_new_string("geo_shape")); |
2014 | 0 | if (!m_osPrecision.empty()) |
2015 | 0 | json_object_object_add( |
2016 | 0 | geometry, "precision", |
2017 | 0 | json_object_new_string(m_osPrecision.c_str())); |
2018 | 0 | } |
2019 | 0 | } |
2020 | |
|
2021 | 0 | json_object *poMeta = nullptr; |
2022 | 0 | json_object *poGeomFields = nullptr; |
2023 | 0 | json_object *poFields = nullptr; |
2024 | 0 | if (!m_osFID.empty()) |
2025 | 0 | { |
2026 | 0 | poMeta = json_object_new_object(); |
2027 | 0 | json_object_object_add(poMeta, "fid", |
2028 | 0 | json_object_new_string(m_osFID.c_str())); |
2029 | 0 | } |
2030 | 0 | for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); i++) |
2031 | 0 | { |
2032 | 0 | OGRGeomFieldDefn *poGeomFieldDefn = |
2033 | 0 | m_poFeatureDefn->GetGeomFieldDefn(i); |
2034 | 0 | if (!m_abIsGeoPoint[i] && poGeomFieldDefn->GetType() != wkbUnknown) |
2035 | 0 | { |
2036 | 0 | if (poMeta == nullptr) |
2037 | 0 | poMeta = json_object_new_object(); |
2038 | 0 | if (poGeomFields == nullptr) |
2039 | 0 | { |
2040 | 0 | poGeomFields = json_object_new_object(); |
2041 | 0 | json_object_object_add(poMeta, "geomfields", poGeomFields); |
2042 | 0 | } |
2043 | 0 | json_object_object_add(poGeomFields, poGeomFieldDefn->GetNameRef(), |
2044 | 0 | json_object_new_string(OGRToOGCGeomType( |
2045 | 0 | poGeomFieldDefn->GetType()))); |
2046 | 0 | } |
2047 | 0 | } |
2048 | 0 | for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++) |
2049 | 0 | { |
2050 | 0 | OGRFieldDefn *poFieldDefn = m_poFeatureDefn->GetFieldDefn(i); |
2051 | 0 | OGRFieldType eType = poFieldDefn->GetType(); |
2052 | 0 | if (eType == OFTIntegerList || eType == OFTInteger64List || |
2053 | 0 | eType == OFTRealList || eType == OFTStringList) |
2054 | 0 | { |
2055 | 0 | if (poMeta == nullptr) |
2056 | 0 | poMeta = json_object_new_object(); |
2057 | 0 | if (poFields == nullptr) |
2058 | 0 | { |
2059 | 0 | poFields = json_object_new_object(); |
2060 | 0 | json_object_object_add(poMeta, "fields", poFields); |
2061 | 0 | } |
2062 | 0 | json_object_object_add( |
2063 | 0 | poFields, poFieldDefn->GetNameRef(), |
2064 | 0 | json_object_new_string(OGR_GetFieldTypeName(eType))); |
2065 | 0 | } |
2066 | 0 | } |
2067 | 0 | if (poMeta) |
2068 | 0 | json_object_object_add(poMapping, "_meta", poMeta); |
2069 | |
|
2070 | 0 | CPLString jsonMap(json_object_to_json_string(map)); |
2071 | 0 | json_object_put(map); |
2072 | | |
2073 | | // Got personally caught by that... |
2074 | 0 | if (CSLCount(m_papszStoredFields) == 1 && |
2075 | 0 | (EQUAL(m_papszStoredFields[0], "YES") || |
2076 | 0 | EQUAL(m_papszStoredFields[0], "TRUE")) && |
2077 | 0 | m_poFeatureDefn->GetFieldIndex(m_papszStoredFields[0]) < 0) |
2078 | 0 | { |
2079 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
2080 | 0 | "STORED_FIELDS=%s was specified. Perhaps you meant " |
2081 | 0 | "STORE_FIELDS=%s instead?", |
2082 | 0 | m_papszStoredFields[0], m_papszStoredFields[0]); |
2083 | 0 | } |
2084 | |
|
2085 | 0 | return jsonMap; |
2086 | 0 | } |
2087 | | |
2088 | | /************************************************************************/ |
2089 | | /* BuildGeoJSONGeometry() */ |
2090 | | /************************************************************************/ |
2091 | | |
2092 | | static void BuildGeoJSONGeometry(json_object *geometry, |
2093 | | const OGRGeometry *poGeom) |
2094 | 0 | { |
2095 | 0 | const int nPrecision = 10; |
2096 | 0 | double dfEps = pow(10.0, -(double)nPrecision); |
2097 | 0 | const char *pszGeomType = ""; |
2098 | 0 | switch (wkbFlatten(poGeom->getGeometryType())) |
2099 | 0 | { |
2100 | 0 | case wkbPoint: |
2101 | 0 | pszGeomType = "point"; |
2102 | 0 | break; |
2103 | 0 | case wkbLineString: |
2104 | 0 | pszGeomType = "linestring"; |
2105 | 0 | break; |
2106 | 0 | case wkbPolygon: |
2107 | 0 | pszGeomType = "polygon"; |
2108 | 0 | break; |
2109 | 0 | case wkbMultiPoint: |
2110 | 0 | pszGeomType = "multipoint"; |
2111 | 0 | break; |
2112 | 0 | case wkbMultiLineString: |
2113 | 0 | pszGeomType = "multilinestring"; |
2114 | 0 | break; |
2115 | 0 | case wkbMultiPolygon: |
2116 | 0 | pszGeomType = "multipolygon"; |
2117 | 0 | break; |
2118 | 0 | case wkbGeometryCollection: |
2119 | 0 | pszGeomType = "geometrycollection"; |
2120 | 0 | break; |
2121 | 0 | default: |
2122 | 0 | break; |
2123 | 0 | } |
2124 | 0 | json_object_object_add(geometry, "type", |
2125 | 0 | json_object_new_string(pszGeomType)); |
2126 | |
|
2127 | 0 | switch (wkbFlatten(poGeom->getGeometryType())) |
2128 | 0 | { |
2129 | 0 | case wkbPoint: |
2130 | 0 | { |
2131 | 0 | const OGRPoint *poPoint = poGeom->toPoint(); |
2132 | 0 | json_object *coordinates = json_object_new_array(); |
2133 | 0 | json_object_object_add(geometry, "coordinates", coordinates); |
2134 | 0 | json_object_array_add(coordinates, |
2135 | 0 | json_object_new_double_with_precision( |
2136 | 0 | poPoint->getX(), nPrecision)); |
2137 | 0 | json_object_array_add(coordinates, |
2138 | 0 | json_object_new_double_with_precision( |
2139 | 0 | poPoint->getY(), nPrecision)); |
2140 | 0 | break; |
2141 | 0 | } |
2142 | | |
2143 | 0 | case wkbLineString: |
2144 | 0 | { |
2145 | 0 | const OGRLineString *poLS = poGeom->toLineString(); |
2146 | 0 | json_object *coordinates = json_object_new_array(); |
2147 | 0 | json_object_object_add(geometry, "coordinates", coordinates); |
2148 | 0 | for (int i = 0; i < poLS->getNumPoints(); i++) |
2149 | 0 | { |
2150 | 0 | json_object *point = json_object_new_array(); |
2151 | 0 | json_object_array_add(coordinates, point); |
2152 | 0 | json_object_array_add( |
2153 | 0 | point, json_object_new_double_with_precision(poLS->getX(i), |
2154 | 0 | nPrecision)); |
2155 | 0 | json_object_array_add( |
2156 | 0 | point, json_object_new_double_with_precision(poLS->getY(i), |
2157 | 0 | nPrecision)); |
2158 | 0 | } |
2159 | 0 | break; |
2160 | 0 | } |
2161 | | |
2162 | 0 | case wkbPolygon: |
2163 | 0 | { |
2164 | 0 | const OGRPolygon *poPoly = poGeom->toPolygon(); |
2165 | 0 | json_object *coordinates = json_object_new_array(); |
2166 | 0 | json_object_object_add(geometry, "coordinates", coordinates); |
2167 | 0 | for (auto &&poLS : *poPoly) |
2168 | 0 | { |
2169 | 0 | json_object *ring = json_object_new_array(); |
2170 | 0 | json_object_array_add(coordinates, ring); |
2171 | 0 | for (int j = 0; j < poLS->getNumPoints(); j++) |
2172 | 0 | { |
2173 | 0 | if (j > 0 && |
2174 | 0 | fabs(poLS->getX(j) - poLS->getX(j - 1)) < dfEps && |
2175 | 0 | fabs(poLS->getY(j) - poLS->getY(j - 1)) < dfEps) |
2176 | 0 | continue; |
2177 | 0 | json_object *point = json_object_new_array(); |
2178 | 0 | json_object_array_add(ring, point); |
2179 | 0 | json_object_array_add(point, |
2180 | 0 | json_object_new_double_with_precision( |
2181 | 0 | poLS->getX(j), nPrecision)); |
2182 | 0 | json_object_array_add(point, |
2183 | 0 | json_object_new_double_with_precision( |
2184 | 0 | poLS->getY(j), nPrecision)); |
2185 | 0 | } |
2186 | 0 | } |
2187 | 0 | break; |
2188 | 0 | } |
2189 | | |
2190 | 0 | case wkbMultiPoint: |
2191 | 0 | { |
2192 | 0 | const OGRMultiPoint *poMP = poGeom->toMultiPoint(); |
2193 | 0 | json_object *coordinates = json_object_new_array(); |
2194 | 0 | json_object_object_add(geometry, "coordinates", coordinates); |
2195 | 0 | for (auto &&poPoint : *poMP) |
2196 | 0 | { |
2197 | 0 | json_object *point = json_object_new_array(); |
2198 | 0 | json_object_array_add(coordinates, point); |
2199 | 0 | json_object_array_add(point, |
2200 | 0 | json_object_new_double_with_precision( |
2201 | 0 | poPoint->getX(), nPrecision)); |
2202 | 0 | json_object_array_add(point, |
2203 | 0 | json_object_new_double_with_precision( |
2204 | 0 | poPoint->getY(), nPrecision)); |
2205 | 0 | } |
2206 | 0 | break; |
2207 | 0 | } |
2208 | | |
2209 | 0 | case wkbMultiLineString: |
2210 | 0 | { |
2211 | 0 | const OGRMultiLineString *poMLS = poGeom->toMultiLineString(); |
2212 | 0 | json_object *coordinates = json_object_new_array(); |
2213 | 0 | json_object_object_add(geometry, "coordinates", coordinates); |
2214 | 0 | for (auto &&poLS : *poMLS) |
2215 | 0 | { |
2216 | 0 | json_object *ls = json_object_new_array(); |
2217 | 0 | json_object_array_add(coordinates, ls); |
2218 | 0 | for (auto &&oPoint : *poLS) |
2219 | 0 | { |
2220 | 0 | json_object *point = json_object_new_array(); |
2221 | 0 | json_object_array_add(ls, point); |
2222 | 0 | json_object_array_add(point, |
2223 | 0 | json_object_new_double_with_precision( |
2224 | 0 | oPoint.getX(), nPrecision)); |
2225 | 0 | json_object_array_add(point, |
2226 | 0 | json_object_new_double_with_precision( |
2227 | 0 | oPoint.getY(), nPrecision)); |
2228 | 0 | } |
2229 | 0 | } |
2230 | 0 | break; |
2231 | 0 | } |
2232 | | |
2233 | 0 | case wkbMultiPolygon: |
2234 | 0 | { |
2235 | 0 | const OGRMultiPolygon *poMP = poGeom->toMultiPolygon(); |
2236 | 0 | json_object *coordinates = json_object_new_array(); |
2237 | 0 | json_object_object_add(geometry, "coordinates", coordinates); |
2238 | 0 | for (auto &&poPoly : *poMP) |
2239 | 0 | { |
2240 | 0 | json_object *poly = json_object_new_array(); |
2241 | 0 | json_object_array_add(coordinates, poly); |
2242 | 0 | for (auto &&poLS : *poPoly) |
2243 | 0 | { |
2244 | 0 | json_object *ring = json_object_new_array(); |
2245 | 0 | json_object_array_add(poly, ring); |
2246 | 0 | for (int k = 0; k < poLS->getNumPoints(); k++) |
2247 | 0 | { |
2248 | 0 | if (k > 0 && |
2249 | 0 | fabs(poLS->getX(k) - poLS->getX(k - 1)) < dfEps && |
2250 | 0 | fabs(poLS->getY(k) - poLS->getY(k - 1)) < dfEps) |
2251 | 0 | continue; |
2252 | 0 | json_object *point = json_object_new_array(); |
2253 | 0 | json_object_array_add(ring, point); |
2254 | 0 | json_object_array_add( |
2255 | 0 | point, json_object_new_double_with_precision( |
2256 | 0 | poLS->getX(k), nPrecision)); |
2257 | 0 | json_object_array_add( |
2258 | 0 | point, json_object_new_double_with_precision( |
2259 | 0 | poLS->getY(k), nPrecision)); |
2260 | 0 | } |
2261 | 0 | } |
2262 | 0 | } |
2263 | 0 | break; |
2264 | 0 | } |
2265 | | |
2266 | 0 | case wkbGeometryCollection: |
2267 | 0 | { |
2268 | 0 | const OGRGeometryCollection *poGC = poGeom->toGeometryCollection(); |
2269 | 0 | json_object *geometries = json_object_new_array(); |
2270 | 0 | json_object_object_add(geometry, "geometries", geometries); |
2271 | 0 | for (auto &&poSubGeom : *poGC) |
2272 | 0 | { |
2273 | 0 | json_object *subgeom = json_object_new_object(); |
2274 | 0 | json_object_array_add(geometries, subgeom); |
2275 | 0 | BuildGeoJSONGeometry(subgeom, poSubGeom); |
2276 | 0 | } |
2277 | 0 | break; |
2278 | 0 | } |
2279 | | |
2280 | 0 | default: |
2281 | 0 | break; |
2282 | 0 | } |
2283 | 0 | } |
2284 | | |
2285 | | /************************************************************************/ |
2286 | | /* WriteMapIfNecessary() */ |
2287 | | /************************************************************************/ |
2288 | | |
2289 | | OGRErr OGRElasticLayer::WriteMapIfNecessary() |
2290 | 0 | { |
2291 | 0 | if (m_bManualMapping) |
2292 | 0 | return OGRERR_NONE; |
2293 | | |
2294 | | // Check to see if the user has elected to only write out the mapping file |
2295 | | // This method will only write out one layer from the vector file in cases |
2296 | | // where there are multiple layers |
2297 | 0 | if (!m_osWriteMapFilename.empty()) |
2298 | 0 | { |
2299 | 0 | if (m_bSerializeMapping) |
2300 | 0 | { |
2301 | 0 | m_bSerializeMapping = false; |
2302 | 0 | CPLString map = BuildMap(); |
2303 | | |
2304 | | // Write the map to a file |
2305 | 0 | VSILFILE *f = VSIFOpenL(m_osWriteMapFilename, "wb"); |
2306 | 0 | if (f) |
2307 | 0 | { |
2308 | 0 | VSIFWriteL(map.c_str(), 1, map.length(), f); |
2309 | 0 | VSIFCloseL(f); |
2310 | 0 | } |
2311 | 0 | } |
2312 | 0 | return OGRERR_NONE; |
2313 | 0 | } |
2314 | | |
2315 | | // Check to see if we have any fields to upload to this index |
2316 | 0 | if (m_osWriteMapFilename.empty() && m_bSerializeMapping) |
2317 | 0 | { |
2318 | 0 | m_bSerializeMapping = false; |
2319 | 0 | CPLString osURL = BuildMappingURL(true); |
2320 | 0 | if (!m_poDS->UploadFile(osURL.c_str(), BuildMap())) |
2321 | 0 | { |
2322 | 0 | return OGRERR_FAILURE; |
2323 | 0 | } |
2324 | 0 | } |
2325 | | |
2326 | 0 | return OGRERR_NONE; |
2327 | 0 | } |
2328 | | |
2329 | | /************************************************************************/ |
2330 | | /* GetContainerForFeature() */ |
2331 | | /************************************************************************/ |
2332 | | |
2333 | | static json_object * |
2334 | | GetContainerForFeature(json_object *poContainer, |
2335 | | const std::vector<CPLString> &aosPath, |
2336 | | std::map<std::vector<CPLString>, json_object *> &oMap) |
2337 | 0 | { |
2338 | 0 | std::vector<CPLString> aosSubPath; |
2339 | 0 | for (int j = 0; j < (int)aosPath.size() - 1; j++) |
2340 | 0 | { |
2341 | 0 | aosSubPath.push_back(aosPath[j]); |
2342 | 0 | std::map<std::vector<CPLString>, json_object *>::iterator oIter = |
2343 | 0 | oMap.find(aosSubPath); |
2344 | 0 | if (oIter == oMap.end()) |
2345 | 0 | { |
2346 | 0 | json_object *poNewContainer = json_object_new_object(); |
2347 | 0 | json_object_object_add(poContainer, aosPath[j], poNewContainer); |
2348 | 0 | oMap[aosSubPath] = poNewContainer; |
2349 | 0 | poContainer = poNewContainer; |
2350 | 0 | } |
2351 | 0 | else |
2352 | 0 | { |
2353 | 0 | poContainer = oIter->second; |
2354 | 0 | } |
2355 | 0 | } |
2356 | 0 | return poContainer; |
2357 | 0 | } |
2358 | | |
2359 | | /************************************************************************/ |
2360 | | /* BuildMappingURL() */ |
2361 | | /************************************************************************/ |
2362 | | CPLString OGRElasticLayer::BuildMappingURL(bool bMappingApi) |
2363 | 0 | { |
2364 | 0 | CPLString osURL = |
2365 | 0 | CPLSPrintf("%s/%s", m_poDS->GetURL(), m_osIndexName.c_str()); |
2366 | 0 | if (bMappingApi) |
2367 | 0 | osURL += "/_mapping"; |
2368 | 0 | if (m_poDS->m_nMajorVersion < 7) |
2369 | 0 | osURL += CPLSPrintf("/%s", m_osMappingName.c_str()); |
2370 | 0 | return osURL; |
2371 | 0 | } |
2372 | | |
2373 | | /************************************************************************/ |
2374 | | /* BuildJSonFromFeature() */ |
2375 | | /************************************************************************/ |
2376 | | |
2377 | | CPLString OGRElasticLayer::BuildJSonFromFeature(OGRFeature *poFeature) |
2378 | 0 | { |
2379 | |
|
2380 | 0 | CPLString fields; |
2381 | 0 | int nJSonFieldIndex = m_poFeatureDefn->GetFieldIndex("_json"); |
2382 | 0 | if (nJSonFieldIndex >= 0 && |
2383 | 0 | poFeature->IsFieldSetAndNotNull(nJSonFieldIndex)) |
2384 | 0 | { |
2385 | 0 | fields = poFeature->GetFieldAsString(nJSonFieldIndex); |
2386 | 0 | } |
2387 | 0 | else |
2388 | 0 | { |
2389 | 0 | json_object *fieldObject = json_object_new_object(); |
2390 | |
|
2391 | 0 | if (poFeature->GetFID() >= 0 && !m_osFID.empty()) |
2392 | 0 | { |
2393 | 0 | json_object_object_add(fieldObject, m_osFID.c_str(), |
2394 | 0 | json_object_new_int64(poFeature->GetFID())); |
2395 | 0 | } |
2396 | |
|
2397 | 0 | std::map<std::vector<CPLString>, json_object *> oMap; |
2398 | |
|
2399 | 0 | for (int i = 0; i < poFeature->GetGeomFieldCount(); i++) |
2400 | 0 | { |
2401 | 0 | OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i); |
2402 | 0 | if (poGeom != nullptr && !poGeom->IsEmpty()) |
2403 | 0 | { |
2404 | 0 | OGREnvelope env; |
2405 | 0 | poGeom->getEnvelope(&env); |
2406 | |
|
2407 | 0 | if (m_apoCT[i] != nullptr) |
2408 | 0 | poGeom->transform(m_apoCT[i]); |
2409 | 0 | else if (env.MinX < -180 || env.MinY < -90 || env.MaxX > 180 || |
2410 | 0 | env.MaxY > 90) |
2411 | 0 | { |
2412 | 0 | CPLErrorOnce( |
2413 | 0 | CE_Warning, CPLE_AppDefined, |
2414 | 0 | "At least one geometry has a bounding box outside " |
2415 | 0 | "of [-180,180] longitude range and/or [-90,90] " |
2416 | 0 | "latitude range. Undefined behavior"); |
2417 | 0 | } |
2418 | |
|
2419 | 0 | std::vector<CPLString> aosPath = m_aaosGeomFieldPaths[i]; |
2420 | 0 | bool bAddGeoJSONType = false; |
2421 | 0 | if (m_abIsGeoPoint[i] && aosPath.size() >= 2 && |
2422 | 0 | aosPath.back() == "coordinates") |
2423 | 0 | { |
2424 | 0 | bAddGeoJSONType = true; |
2425 | 0 | aosPath.resize((int)aosPath.size() - 1); |
2426 | 0 | } |
2427 | |
|
2428 | 0 | json_object *poContainer = |
2429 | 0 | GetContainerForFeature(fieldObject, aosPath, oMap); |
2430 | 0 | const char *pszLastComponent = aosPath.back(); |
2431 | |
|
2432 | 0 | if (m_abIsGeoPoint[i]) |
2433 | 0 | { |
2434 | 0 | json_object *coordinates = json_object_new_array(); |
2435 | 0 | const int nPrecision = 10; |
2436 | 0 | json_object_array_add( |
2437 | 0 | coordinates, |
2438 | 0 | json_object_new_double_with_precision( |
2439 | 0 | (env.MaxX + env.MinX) * 0.5, nPrecision)); |
2440 | 0 | json_object_array_add( |
2441 | 0 | coordinates, |
2442 | 0 | json_object_new_double_with_precision( |
2443 | 0 | (env.MaxY + env.MinY) * 0.5, nPrecision)); |
2444 | |
|
2445 | 0 | if (bAddGeoJSONType) |
2446 | 0 | { |
2447 | 0 | json_object *geometry = json_object_new_object(); |
2448 | 0 | json_object_object_add(poContainer, pszLastComponent, |
2449 | 0 | geometry); |
2450 | 0 | json_object_object_add(geometry, "type", |
2451 | 0 | json_object_new_string("Point")); |
2452 | 0 | json_object_object_add(geometry, "coordinates", |
2453 | 0 | coordinates); |
2454 | 0 | } |
2455 | 0 | else |
2456 | 0 | { |
2457 | 0 | json_object_object_add(poContainer, pszLastComponent, |
2458 | 0 | coordinates); |
2459 | 0 | } |
2460 | 0 | } |
2461 | 0 | else |
2462 | 0 | { |
2463 | 0 | if (m_bGeoShapeAsGeoJSON) |
2464 | 0 | { |
2465 | 0 | json_object *geometry = json_object_new_object(); |
2466 | 0 | json_object_object_add(poContainer, pszLastComponent, |
2467 | 0 | geometry); |
2468 | 0 | BuildGeoJSONGeometry(geometry, poGeom); |
2469 | 0 | } |
2470 | 0 | else |
2471 | 0 | { |
2472 | 0 | char *pszWKT = nullptr; |
2473 | 0 | poGeom->exportToWkt(&pszWKT); |
2474 | 0 | json_object_object_add(poContainer, pszLastComponent, |
2475 | 0 | json_object_new_string(pszWKT)); |
2476 | 0 | CPLFree(pszWKT); |
2477 | 0 | } |
2478 | 0 | } |
2479 | 0 | } |
2480 | 0 | } |
2481 | |
|
2482 | 0 | if (m_osMappingName == "FeatureCollection") |
2483 | 0 | { |
2484 | 0 | if (poFeature->GetGeomFieldCount() == 1 && |
2485 | 0 | poFeature->GetGeomFieldRef(0)) |
2486 | 0 | { |
2487 | 0 | json_object_object_add(fieldObject, "type", |
2488 | 0 | json_object_new_string("Feature")); |
2489 | 0 | } |
2490 | |
|
2491 | 0 | std::vector<CPLString> aosPath; |
2492 | 0 | aosPath.push_back("properties"); |
2493 | 0 | aosPath.push_back("dummy"); |
2494 | 0 | GetContainerForFeature(fieldObject, aosPath, oMap); |
2495 | 0 | } |
2496 | | |
2497 | | // For every field (except _id) |
2498 | 0 | int fieldCount = m_poFeatureDefn->GetFieldCount(); |
2499 | 0 | for (int i = 1; i < fieldCount; i++) |
2500 | 0 | { |
2501 | 0 | if (!poFeature->IsFieldSet(i)) |
2502 | 0 | { |
2503 | 0 | continue; |
2504 | 0 | } |
2505 | | |
2506 | 0 | json_object *poContainer = |
2507 | 0 | GetContainerForFeature(fieldObject, m_aaosFieldPaths[i], oMap); |
2508 | 0 | const char *pszLastComponent = m_aaosFieldPaths[i].back(); |
2509 | |
|
2510 | 0 | if (poFeature->IsFieldNull(i)) |
2511 | 0 | { |
2512 | 0 | json_object_object_add(poContainer, pszLastComponent, nullptr); |
2513 | 0 | continue; |
2514 | 0 | } |
2515 | | |
2516 | 0 | switch (m_poFeatureDefn->GetFieldDefn(i)->GetType()) |
2517 | 0 | { |
2518 | 0 | case OFTInteger: |
2519 | 0 | if (m_poFeatureDefn->GetFieldDefn(i)->GetSubType() == |
2520 | 0 | OFSTBoolean) |
2521 | 0 | json_object_object_add( |
2522 | 0 | poContainer, pszLastComponent, |
2523 | 0 | json_object_new_boolean( |
2524 | 0 | poFeature->GetFieldAsInteger(i))); |
2525 | 0 | else |
2526 | 0 | json_object_object_add( |
2527 | 0 | poContainer, pszLastComponent, |
2528 | 0 | json_object_new_int( |
2529 | 0 | poFeature->GetFieldAsInteger(i))); |
2530 | 0 | break; |
2531 | 0 | case OFTInteger64: |
2532 | 0 | json_object_object_add( |
2533 | 0 | poContainer, pszLastComponent, |
2534 | 0 | json_object_new_int64( |
2535 | 0 | poFeature->GetFieldAsInteger64(i))); |
2536 | 0 | break; |
2537 | 0 | case OFTReal: |
2538 | 0 | json_object_object_add( |
2539 | 0 | poContainer, pszLastComponent, |
2540 | 0 | json_object_new_double_with_significant_figures( |
2541 | 0 | poFeature->GetFieldAsDouble(i), -1)); |
2542 | 0 | break; |
2543 | 0 | case OFTIntegerList: |
2544 | 0 | { |
2545 | 0 | int nCount = 0; |
2546 | 0 | const int *panValues = |
2547 | 0 | poFeature->GetFieldAsIntegerList(i, &nCount); |
2548 | 0 | json_object *poArray = json_object_new_array(); |
2549 | 0 | for (int j = 0; j < nCount; j++) |
2550 | 0 | json_object_array_add( |
2551 | 0 | poArray, json_object_new_int(panValues[j])); |
2552 | 0 | json_object_object_add(poContainer, pszLastComponent, |
2553 | 0 | poArray); |
2554 | 0 | break; |
2555 | 0 | } |
2556 | 0 | case OFTInteger64List: |
2557 | 0 | { |
2558 | 0 | int nCount = 0; |
2559 | 0 | const GIntBig *panValues = |
2560 | 0 | poFeature->GetFieldAsInteger64List(i, &nCount); |
2561 | 0 | json_object *poArray = json_object_new_array(); |
2562 | 0 | for (int j = 0; j < nCount; j++) |
2563 | 0 | json_object_array_add( |
2564 | 0 | poArray, json_object_new_int64(panValues[j])); |
2565 | 0 | json_object_object_add(poContainer, pszLastComponent, |
2566 | 0 | poArray); |
2567 | 0 | break; |
2568 | 0 | } |
2569 | 0 | case OFTRealList: |
2570 | 0 | { |
2571 | 0 | int nCount = 0; |
2572 | 0 | const double *padfValues = |
2573 | 0 | poFeature->GetFieldAsDoubleList(i, &nCount); |
2574 | 0 | json_object *poArray = json_object_new_array(); |
2575 | 0 | for (int j = 0; j < nCount; j++) |
2576 | 0 | json_object_array_add( |
2577 | 0 | poArray, |
2578 | 0 | json_object_new_double_with_significant_figures( |
2579 | 0 | padfValues[j], -1)); |
2580 | 0 | json_object_object_add(poContainer, pszLastComponent, |
2581 | 0 | poArray); |
2582 | 0 | break; |
2583 | 0 | } |
2584 | 0 | case OFTStringList: |
2585 | 0 | { |
2586 | 0 | char **papszValues = poFeature->GetFieldAsStringList(i); |
2587 | 0 | json_object *poArray = json_object_new_array(); |
2588 | 0 | for (int j = 0; papszValues[j] != nullptr; j++) |
2589 | 0 | json_object_array_add( |
2590 | 0 | poArray, json_object_new_string(papszValues[j])); |
2591 | 0 | json_object_object_add(poContainer, pszLastComponent, |
2592 | 0 | poArray); |
2593 | 0 | break; |
2594 | 0 | } |
2595 | 0 | case OFTBinary: |
2596 | 0 | { |
2597 | 0 | int nCount = 0; |
2598 | 0 | GByte *pabyVal = poFeature->GetFieldAsBinary(i, &nCount); |
2599 | 0 | char *pszVal = CPLBase64Encode(nCount, pabyVal); |
2600 | 0 | json_object_object_add(poContainer, pszLastComponent, |
2601 | 0 | json_object_new_string(pszVal)); |
2602 | 0 | CPLFree(pszVal); |
2603 | 0 | break; |
2604 | 0 | } |
2605 | 0 | case OFTDateTime: |
2606 | 0 | { |
2607 | 0 | int nYear = 0; |
2608 | 0 | int nMonth = 0; |
2609 | 0 | int nDay = 0; |
2610 | 0 | int nHour = 0; |
2611 | 0 | int nMin = 0; |
2612 | 0 | int nTZ = 0; |
2613 | 0 | float fSec = 0.0f; |
2614 | 0 | poFeature->GetFieldAsDateTime(i, &nYear, &nMonth, &nDay, |
2615 | 0 | &nHour, &nMin, &fSec, &nTZ); |
2616 | 0 | if (nTZ == 0) |
2617 | 0 | { |
2618 | 0 | json_object_object_add( |
2619 | 0 | poContainer, pszLastComponent, |
2620 | 0 | json_object_new_string(CPLSPrintf( |
2621 | 0 | "%04d/%02d/%02d %02d:%02d:%06.3f", nYear, |
2622 | 0 | nMonth, nDay, nHour, nMin, fSec))); |
2623 | 0 | } |
2624 | 0 | else |
2625 | 0 | { |
2626 | 0 | const int TZOffset = std::abs(nTZ - 100) * 15; |
2627 | 0 | const int TZHour = TZOffset / 60; |
2628 | 0 | const int TZMinute = TZOffset - TZHour * 60; |
2629 | 0 | json_object_object_add( |
2630 | 0 | poContainer, pszLastComponent, |
2631 | 0 | json_object_new_string(CPLSPrintf( |
2632 | 0 | "%04d/%02d/%02d %02d:%02d:%06.3f%c%02d:%02d", |
2633 | 0 | nYear, nMonth, nDay, nHour, nMin, fSec, |
2634 | 0 | (nTZ >= 100) ? '+' : '-', TZHour, TZMinute))); |
2635 | 0 | } |
2636 | 0 | break; |
2637 | 0 | } |
2638 | 0 | default: |
2639 | 0 | { |
2640 | 0 | const char *pszVal = poFeature->GetFieldAsString(i); |
2641 | 0 | json_object_object_add(poContainer, pszLastComponent, |
2642 | 0 | json_object_new_string(pszVal)); |
2643 | 0 | } |
2644 | 0 | } |
2645 | 0 | } |
2646 | | |
2647 | | // Build the field string |
2648 | 0 | fields = json_object_to_json_string(fieldObject); |
2649 | 0 | json_object_put(fieldObject); |
2650 | 0 | } |
2651 | | |
2652 | 0 | return fields; |
2653 | 0 | } |
2654 | | |
2655 | | /************************************************************************/ |
2656 | | /* ICreateFeature() */ |
2657 | | /************************************************************************/ |
2658 | | |
2659 | | OGRErr OGRElasticLayer::ICreateFeature(OGRFeature *poFeature) |
2660 | 0 | { |
2661 | 0 | if (m_poDS->GetAccess() != GA_Update) |
2662 | 0 | { |
2663 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
2664 | 0 | "Dataset opened in read-only mode"); |
2665 | 0 | return OGRERR_FAILURE; |
2666 | 0 | } |
2667 | | |
2668 | 0 | FinalizeFeatureDefn(); |
2669 | |
|
2670 | 0 | if (WriteMapIfNecessary() != OGRERR_NONE) |
2671 | 0 | return OGRERR_FAILURE; |
2672 | | |
2673 | 0 | if (!m_osWriteMapFilename.empty()) |
2674 | 0 | return OGRERR_NONE; |
2675 | | |
2676 | 0 | if (poFeature->GetFID() < 0) |
2677 | 0 | { |
2678 | 0 | if (m_nNextFID < 0) |
2679 | 0 | m_nNextFID = GetFeatureCount(FALSE); |
2680 | 0 | poFeature->SetFID(++m_nNextFID); |
2681 | 0 | } |
2682 | |
|
2683 | 0 | CPLString osFields(BuildJSonFromFeature(poFeature)); |
2684 | |
|
2685 | 0 | const char *pszId = nullptr; |
2686 | 0 | if (poFeature->IsFieldSetAndNotNull(0) && !m_bIgnoreSourceID) |
2687 | 0 | pszId = poFeature->GetFieldAsString(0); |
2688 | | |
2689 | | // Check to see if we're using bulk uploading |
2690 | 0 | if (m_nBulkUpload > 0) |
2691 | 0 | { |
2692 | 0 | m_osBulkContent += |
2693 | 0 | CPLSPrintf("{\"index\" :{\"_index\":\"%s\"", m_osIndexName.c_str()); |
2694 | 0 | if (m_poDS->m_nMajorVersion < 7) |
2695 | 0 | m_osBulkContent += |
2696 | 0 | CPLSPrintf(", \"_type\":\"%s\"", m_osMappingName.c_str()); |
2697 | 0 | if (pszId) |
2698 | 0 | m_osBulkContent += CPLSPrintf(",\"_id\":\"%s\"", pszId); |
2699 | 0 | m_osBulkContent += "}}\n" + osFields + "\n\n"; |
2700 | | |
2701 | | // Only push the data if we are over our bulk upload limit |
2702 | 0 | if ((int)m_osBulkContent.length() > m_nBulkUpload) |
2703 | 0 | { |
2704 | 0 | if (!PushIndex()) |
2705 | 0 | { |
2706 | 0 | return OGRERR_FAILURE; |
2707 | 0 | } |
2708 | 0 | } |
2709 | 0 | } |
2710 | 0 | else |
2711 | 0 | { |
2712 | | // Fall back to using single item upload for every feature. |
2713 | 0 | CPLString osURL(BuildMappingURL(false)); |
2714 | 0 | if (pszId) |
2715 | 0 | osURL += CPLSPrintf("/%s", pszId); |
2716 | 0 | json_object *poRes = m_poDS->RunRequest(osURL, osFields); |
2717 | 0 | if (poRes == nullptr) |
2718 | 0 | { |
2719 | 0 | return OGRERR_FAILURE; |
2720 | 0 | } |
2721 | 0 | if (pszId == nullptr) |
2722 | 0 | { |
2723 | 0 | json_object *poId = CPL_json_object_object_get(poRes, "_id"); |
2724 | 0 | if (poId != nullptr && |
2725 | 0 | json_object_get_type(poId) == json_type_string) |
2726 | 0 | { |
2727 | 0 | pszId = json_object_get_string(poId); |
2728 | 0 | poFeature->SetField(0, pszId); |
2729 | 0 | } |
2730 | 0 | } |
2731 | 0 | json_object_put(poRes); |
2732 | 0 | } |
2733 | | |
2734 | 0 | return OGRERR_NONE; |
2735 | 0 | } |
2736 | | |
2737 | | /************************************************************************/ |
2738 | | /* ISetFeature() */ |
2739 | | /************************************************************************/ |
2740 | | |
2741 | | OGRErr OGRElasticLayer::ISetFeature(OGRFeature *poFeature) |
2742 | 0 | { |
2743 | 0 | if (m_poDS->GetAccess() != GA_Update) |
2744 | 0 | { |
2745 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
2746 | 0 | "Dataset opened in read-only mode"); |
2747 | 0 | return OGRERR_FAILURE; |
2748 | 0 | } |
2749 | | |
2750 | 0 | FinalizeFeatureDefn(); |
2751 | |
|
2752 | 0 | if (!poFeature->IsFieldSetAndNotNull(0)) |
2753 | 0 | { |
2754 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "_id field not set"); |
2755 | 0 | return OGRERR_FAILURE; |
2756 | 0 | } |
2757 | 0 | if (poFeature->GetFID() < 0 && !m_osFID.empty()) |
2758 | 0 | { |
2759 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Invalid FID"); |
2760 | 0 | return OGRERR_FAILURE; |
2761 | 0 | } |
2762 | | |
2763 | 0 | if (WriteMapIfNecessary() != OGRERR_NONE) |
2764 | 0 | return OGRERR_FAILURE; |
2765 | 0 | PushIndex(); |
2766 | |
|
2767 | 0 | CPLString osFields(BuildJSonFromFeature(poFeature)); |
2768 | | |
2769 | | // TODO? we should theoretically detect if the provided _id doesn't exist |
2770 | 0 | CPLString osURL( |
2771 | 0 | CPLSPrintf("%s/%s", m_poDS->GetURL(), m_osIndexName.c_str())); |
2772 | 0 | if (m_poDS->m_nMajorVersion < 7) |
2773 | 0 | osURL += CPLSPrintf("/%s", m_osMappingName.c_str()); |
2774 | 0 | osURL += CPLSPrintf("/%s", poFeature->GetFieldAsString(0)); |
2775 | 0 | json_object *poRes = m_poDS->RunRequest(osURL, osFields); |
2776 | 0 | if (poRes == nullptr) |
2777 | 0 | { |
2778 | 0 | return OGRERR_FAILURE; |
2779 | 0 | } |
2780 | | // CPLDebug("ES", "SetFeature(): %s", json_object_to_json_string(poRes)); |
2781 | 0 | json_object_put(poRes); |
2782 | |
|
2783 | 0 | return OGRERR_NONE; |
2784 | 0 | } |
2785 | | |
2786 | | /************************************************************************/ |
2787 | | /* IUpsertFeature() */ |
2788 | | /************************************************************************/ |
2789 | | |
2790 | | OGRErr OGRElasticLayer::IUpsertFeature(OGRFeature *poFeature) |
2791 | 0 | { |
2792 | 0 | if (m_poDS->GetAccess() != GA_Update) |
2793 | 0 | { |
2794 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
2795 | 0 | "Dataset opened in read-only mode"); |
2796 | 0 | return OGRERR_FAILURE; |
2797 | 0 | } |
2798 | | |
2799 | 0 | FinalizeFeatureDefn(); |
2800 | |
|
2801 | 0 | if (WriteMapIfNecessary() != OGRERR_NONE) |
2802 | 0 | return OGRERR_FAILURE; |
2803 | | |
2804 | 0 | if (!m_osWriteMapFilename.empty()) |
2805 | 0 | return OGRERR_NONE; |
2806 | | |
2807 | 0 | if (poFeature->GetFID() < 0) |
2808 | 0 | { |
2809 | 0 | if (m_nNextFID < 0) |
2810 | 0 | m_nNextFID = GetFeatureCount(FALSE); |
2811 | 0 | poFeature->SetFID(++m_nNextFID); |
2812 | 0 | } |
2813 | |
|
2814 | 0 | CPLString osFields(BuildJSonFromFeature(poFeature)); |
2815 | |
|
2816 | 0 | const char *pszId = nullptr; |
2817 | 0 | if (poFeature->IsFieldSetAndNotNull(0)) |
2818 | 0 | { |
2819 | 0 | pszId = poFeature->GetFieldAsString(0); |
2820 | 0 | } |
2821 | 0 | else |
2822 | 0 | { |
2823 | 0 | return OGRERR_FAILURE; |
2824 | 0 | } |
2825 | | |
2826 | | // Check to see if we're using bulk uploading |
2827 | 0 | if (m_nBulkUpload > 0) |
2828 | 0 | { |
2829 | 0 | m_osBulkContent += |
2830 | 0 | CPLSPrintf("{\"update\":{\"_index\":\"%s\",\"_id\":\"%s\"", |
2831 | 0 | m_osIndexName.c_str(), pszId); |
2832 | 0 | if (m_poDS->m_nMajorVersion < 7) |
2833 | 0 | { |
2834 | 0 | m_osBulkContent += |
2835 | 0 | CPLSPrintf(", \"_type\":\"%s\"", m_osMappingName.c_str()); |
2836 | 0 | } |
2837 | 0 | m_osBulkContent += |
2838 | 0 | "}}\n{\"doc\":" + osFields + ",\"doc_as_upsert\":true}\n\n"; |
2839 | | |
2840 | | // Only push the data if we are over our bulk upload limit |
2841 | 0 | if (m_osBulkContent.length() > static_cast<size_t>(m_nBulkUpload)) |
2842 | 0 | { |
2843 | 0 | if (!PushIndex()) |
2844 | 0 | { |
2845 | 0 | return OGRERR_FAILURE; |
2846 | 0 | } |
2847 | 0 | } |
2848 | 0 | } |
2849 | 0 | else |
2850 | 0 | { |
2851 | | // Fall back to using single item upload for every feature. |
2852 | 0 | CPLString osURL(BuildMappingURL(false)); |
2853 | 0 | if (m_poDS->m_nMajorVersion < 7) |
2854 | 0 | { |
2855 | 0 | osURL += CPLSPrintf("/%s/_update", pszId); |
2856 | 0 | } |
2857 | 0 | else |
2858 | 0 | { |
2859 | 0 | osURL += CPLSPrintf("/_update/%s", pszId); |
2860 | 0 | } |
2861 | |
|
2862 | 0 | const CPLString osUpdate = |
2863 | 0 | CPLSPrintf("{\"doc\":%s,\"doc_as_upsert\":true}", osFields.c_str()); |
2864 | 0 | const CPLString osMethod = "POST"; |
2865 | 0 | if (!m_poDS->UploadFile(osURL, osUpdate, osMethod)) |
2866 | 0 | { |
2867 | 0 | return OGRERR_FAILURE; |
2868 | 0 | } |
2869 | 0 | } |
2870 | | |
2871 | 0 | return OGRERR_NONE; |
2872 | 0 | } |
2873 | | |
2874 | | /************************************************************************/ |
2875 | | /* PushIndex() */ |
2876 | | /************************************************************************/ |
2877 | | |
2878 | | bool OGRElasticLayer::PushIndex() |
2879 | 0 | { |
2880 | 0 | if (m_osBulkContent.empty()) |
2881 | 0 | { |
2882 | 0 | return true; |
2883 | 0 | } |
2884 | | |
2885 | 0 | const bool bRet = m_poDS->UploadFile( |
2886 | 0 | CPLSPrintf("%s/_bulk", m_poDS->GetURL()), m_osBulkContent); |
2887 | 0 | m_osBulkContent.clear(); |
2888 | |
|
2889 | 0 | return bRet; |
2890 | 0 | } |
2891 | | |
2892 | | /************************************************************************/ |
2893 | | /* CreateField() */ |
2894 | | /************************************************************************/ |
2895 | | |
2896 | | OGRErr OGRElasticLayer::CreateField(const OGRFieldDefn *poFieldDefn, |
2897 | | int /*bApproxOK*/) |
2898 | 0 | { |
2899 | 0 | if (m_poDS->GetAccess() != GA_Update) |
2900 | 0 | { |
2901 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
2902 | 0 | "Dataset opened in read-only mode"); |
2903 | 0 | return OGRERR_FAILURE; |
2904 | 0 | } |
2905 | | |
2906 | 0 | FinalizeFeatureDefn(); |
2907 | 0 | ResetReading(); |
2908 | |
|
2909 | 0 | if (m_poFeatureDefn->GetFieldIndex(poFieldDefn->GetNameRef()) >= 0) |
2910 | 0 | { |
2911 | 0 | if (!EQUAL(poFieldDefn->GetNameRef(), "_id") && |
2912 | 0 | !EQUAL(poFieldDefn->GetNameRef(), "_json")) |
2913 | 0 | { |
2914 | 0 | CPLError( |
2915 | 0 | CE_Failure, CPLE_AppDefined, |
2916 | 0 | "CreateField() called with an already existing field name: %s", |
2917 | 0 | poFieldDefn->GetNameRef()); |
2918 | 0 | } |
2919 | 0 | return OGRERR_FAILURE; |
2920 | 0 | } |
2921 | | |
2922 | 0 | std::vector<CPLString> aosPath; |
2923 | 0 | if (m_osMappingName == "FeatureCollection") |
2924 | 0 | aosPath.push_back("properties"); |
2925 | |
|
2926 | 0 | if (m_bDotAsNestedField) |
2927 | 0 | { |
2928 | 0 | char **papszTokens = |
2929 | 0 | CSLTokenizeString2(poFieldDefn->GetNameRef(), ".", 0); |
2930 | 0 | for (int i = 0; papszTokens[i]; i++) |
2931 | 0 | aosPath.push_back(papszTokens[i]); |
2932 | 0 | CSLDestroy(papszTokens); |
2933 | 0 | } |
2934 | 0 | else |
2935 | 0 | aosPath.push_back(poFieldDefn->GetNameRef()); |
2936 | |
|
2937 | 0 | AddFieldDefn(poFieldDefn->GetNameRef(), poFieldDefn->GetType(), aosPath, |
2938 | 0 | poFieldDefn->GetSubType()); |
2939 | |
|
2940 | 0 | m_bSerializeMapping = true; |
2941 | |
|
2942 | 0 | return OGRERR_NONE; |
2943 | 0 | } |
2944 | | |
2945 | | /************************************************************************/ |
2946 | | /* CreateGeomField() */ |
2947 | | /************************************************************************/ |
2948 | | |
2949 | | OGRErr OGRElasticLayer::CreateGeomField(const OGRGeomFieldDefn *poFieldIn, |
2950 | | int /*bApproxOK*/) |
2951 | | |
2952 | 0 | { |
2953 | 0 | if (m_poDS->GetAccess() != GA_Update) |
2954 | 0 | { |
2955 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
2956 | 0 | "Dataset opened in read-only mode"); |
2957 | 0 | return OGRERR_FAILURE; |
2958 | 0 | } |
2959 | | |
2960 | 0 | FinalizeFeatureDefn(); |
2961 | 0 | ResetReading(); |
2962 | |
|
2963 | 0 | if (m_poFeatureDefn->GetGeomFieldIndex(poFieldIn->GetNameRef()) >= 0) |
2964 | 0 | { |
2965 | 0 | CPLError( |
2966 | 0 | CE_Failure, CPLE_AppDefined, |
2967 | 0 | "CreateGeomField() called with an already existing field name: %s", |
2968 | 0 | poFieldIn->GetNameRef()); |
2969 | 0 | return OGRERR_FAILURE; |
2970 | 0 | } |
2971 | | |
2972 | 0 | OGRGeomFieldDefn oFieldDefn(poFieldIn); |
2973 | 0 | auto poSRSOri = poFieldIn->GetSpatialRef(); |
2974 | 0 | if (poSRSOri) |
2975 | 0 | { |
2976 | 0 | auto poSRS = poSRSOri->Clone(); |
2977 | 0 | poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
2978 | 0 | oFieldDefn.SetSpatialRef(poSRS); |
2979 | 0 | poSRS->Release(); |
2980 | 0 | } |
2981 | 0 | if (EQUAL(oFieldDefn.GetNameRef(), "")) |
2982 | 0 | oFieldDefn.SetName("geometry"); |
2983 | |
|
2984 | 0 | std::vector<CPLString> aosPath; |
2985 | 0 | if (m_bDotAsNestedField) |
2986 | 0 | { |
2987 | 0 | char **papszTokens = |
2988 | 0 | CSLTokenizeString2(oFieldDefn.GetNameRef(), ".", 0); |
2989 | 0 | for (int i = 0; papszTokens[i]; i++) |
2990 | 0 | aosPath.push_back(papszTokens[i]); |
2991 | 0 | CSLDestroy(papszTokens); |
2992 | 0 | } |
2993 | 0 | else |
2994 | 0 | aosPath.push_back(oFieldDefn.GetNameRef()); |
2995 | |
|
2996 | 0 | if (m_eGeomTypeMapping == ES_GEOMTYPE_GEO_SHAPE || |
2997 | 0 | (m_eGeomTypeMapping == ES_GEOMTYPE_AUTO && |
2998 | 0 | poFieldIn->GetType() != wkbPoint)) |
2999 | 0 | { |
3000 | 0 | m_abIsGeoPoint.push_back(FALSE); |
3001 | 0 | } |
3002 | 0 | else |
3003 | 0 | { |
3004 | 0 | m_abIsGeoPoint.push_back(TRUE); |
3005 | 0 | aosPath.push_back("coordinates"); |
3006 | 0 | } |
3007 | |
|
3008 | 0 | m_aaosGeomFieldPaths.push_back(aosPath); |
3009 | |
|
3010 | 0 | m_aosMapToGeomFieldIndex[BuildPathFromArray(aosPath)] = |
3011 | 0 | m_poFeatureDefn->GetGeomFieldCount(); |
3012 | |
|
3013 | 0 | m_poFeatureDefn->AddGeomFieldDefn(&oFieldDefn); |
3014 | |
|
3015 | 0 | OGRCoordinateTransformation *poCT = nullptr; |
3016 | 0 | if (oFieldDefn.GetSpatialRef() != nullptr) |
3017 | 0 | { |
3018 | 0 | OGRSpatialReference oSRS_WGS84; |
3019 | 0 | oSRS_WGS84.SetFromUserInput(SRS_WKT_WGS84_LAT_LONG); |
3020 | 0 | oSRS_WGS84.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
3021 | 0 | if (!oSRS_WGS84.IsSame(oFieldDefn.GetSpatialRef())) |
3022 | 0 | { |
3023 | 0 | poCT = OGRCreateCoordinateTransformation(oFieldDefn.GetSpatialRef(), |
3024 | 0 | &oSRS_WGS84); |
3025 | 0 | if (poCT == nullptr) |
3026 | 0 | { |
3027 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
3028 | 0 | "On-the-fly reprojection to WGS84 long/lat would be " |
3029 | 0 | "needed, but instantiation of transformer failed"); |
3030 | 0 | } |
3031 | 0 | } |
3032 | 0 | } |
3033 | 0 | else |
3034 | 0 | { |
3035 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
3036 | 0 | "No SRS given for geometry column %s. SRS is assumed to " |
3037 | 0 | "be EPSG:4326 (WGS84 long/lat)", |
3038 | 0 | oFieldDefn.GetNameRef()); |
3039 | 0 | } |
3040 | |
|
3041 | 0 | m_apoCT.push_back(poCT); |
3042 | |
|
3043 | 0 | m_bSerializeMapping = true; |
3044 | |
|
3045 | 0 | return OGRERR_NONE; |
3046 | 0 | } |
3047 | | |
3048 | | /************************************************************************/ |
3049 | | /* TestCapability() */ |
3050 | | /************************************************************************/ |
3051 | | |
3052 | | int OGRElasticLayer::TestCapability(const char *pszCap) const |
3053 | 0 | { |
3054 | 0 | if (EQUAL(pszCap, OLCFastFeatureCount)) |
3055 | 0 | return m_poAttrQuery == nullptr && m_poFilterGeom == nullptr; |
3056 | | |
3057 | 0 | else if (EQUAL(pszCap, OLCStringsAsUTF8)) |
3058 | 0 | return TRUE; |
3059 | | |
3060 | 0 | else if (EQUAL(pszCap, OLCSequentialWrite) || |
3061 | 0 | EQUAL(pszCap, OLCUpsertFeature) || EQUAL(pszCap, OLCRandomWrite)) |
3062 | 0 | return m_poDS->GetAccess() == GA_Update; |
3063 | 0 | else if (EQUAL(pszCap, OLCCreateField) || EQUAL(pszCap, OLCCreateGeomField)) |
3064 | 0 | return m_poDS->GetAccess() == GA_Update; |
3065 | 0 | else |
3066 | 0 | return FALSE; |
3067 | 0 | } |
3068 | | |
3069 | | /************************************************************************/ |
3070 | | /* AddTimeoutTerminateAfterToURL() */ |
3071 | | /************************************************************************/ |
3072 | | |
3073 | | void OGRElasticLayer::AddTimeoutTerminateAfterToURL(CPLString &osURL) |
3074 | 0 | { |
3075 | 0 | if (!m_osSingleQueryTimeout.empty()) |
3076 | 0 | osURL += "&timeout=" + m_osSingleQueryTimeout; |
3077 | 0 | if (!m_osSingleQueryTerminateAfter.empty()) |
3078 | 0 | osURL += "&terminate_after=" + m_osSingleQueryTerminateAfter; |
3079 | 0 | } |
3080 | | |
3081 | | /************************************************************************/ |
3082 | | /* GetFeatureCount() */ |
3083 | | /************************************************************************/ |
3084 | | |
3085 | | GIntBig OGRElasticLayer::GetFeatureCount(int bForce) |
3086 | 0 | { |
3087 | 0 | if (m_bFilterMustBeClientSideEvaluated) |
3088 | 0 | { |
3089 | 0 | m_bUseSingleQueryParams = true; |
3090 | 0 | const auto nRet = OGRLayer::GetFeatureCount(bForce); |
3091 | 0 | m_bUseSingleQueryParams = false; |
3092 | 0 | return nRet; |
3093 | 0 | } |
3094 | | |
3095 | 0 | json_object *poResponse = nullptr; |
3096 | 0 | CPLString osURL(CPLSPrintf("%s", m_poDS->GetURL())); |
3097 | 0 | CPLString osFilter = ""; |
3098 | 0 | if (!m_osESSearch.empty()) |
3099 | 0 | { |
3100 | 0 | if (m_osESSearch[0] != '{') |
3101 | 0 | return OGRLayer::GetFeatureCount(bForce); |
3102 | 0 | osURL += "/_search?pretty"; |
3103 | 0 | osFilter = "{ \"size\": 0 "; |
3104 | 0 | if (m_osESSearch == "{}") |
3105 | 0 | osFilter += '}'; |
3106 | 0 | else |
3107 | 0 | osFilter += ", " + m_osESSearch.substr(1); |
3108 | 0 | } |
3109 | 0 | else if ((m_poSpatialFilter && m_osJSONFilter.empty()) || m_poJSONFilter) |
3110 | 0 | { |
3111 | 0 | osFilter = BuildQuery(true); |
3112 | 0 | osURL += CPLSPrintf("/%s", m_osIndexName.c_str()); |
3113 | 0 | if (m_poDS->m_nMajorVersion < 7) |
3114 | 0 | osURL += CPLSPrintf("/%s", m_osMappingName.c_str()); |
3115 | 0 | if (m_poDS->m_nMajorVersion >= 5 && m_osSingleQueryTimeout.empty()) |
3116 | 0 | { |
3117 | 0 | osURL += "/_count?pretty"; |
3118 | 0 | } |
3119 | 0 | else |
3120 | 0 | { |
3121 | 0 | osURL += "/_search?pretty"; |
3122 | 0 | } |
3123 | 0 | } |
3124 | 0 | else if (!m_osJSONFilter.empty()) |
3125 | 0 | { |
3126 | 0 | osURL += CPLSPrintf("/%s", m_osIndexName.c_str()); |
3127 | 0 | if (m_poDS->m_nMajorVersion < 7) |
3128 | 0 | osURL += CPLSPrintf("/%s", m_osMappingName.c_str()); |
3129 | 0 | osURL += "/_search?pretty"; |
3130 | 0 | osFilter = ("{ \"size\": 0, " + m_osJSONFilter.substr(1)); |
3131 | 0 | } |
3132 | 0 | else |
3133 | 0 | { |
3134 | 0 | osURL += CPLSPrintf("/%s", m_osIndexName.c_str()); |
3135 | 0 | if (m_poDS->m_nMajorVersion < 7) |
3136 | 0 | osURL += CPLSPrintf("/%s", m_osMappingName.c_str()); |
3137 | 0 | if (m_osSingleQueryTimeout.empty()) |
3138 | 0 | { |
3139 | 0 | osURL += "/_count?pretty"; |
3140 | 0 | } |
3141 | 0 | else |
3142 | 0 | { |
3143 | 0 | osFilter = "{ \"size\": 0 }"; |
3144 | 0 | osURL += CPLSPrintf("/_search?pretty"); |
3145 | 0 | } |
3146 | 0 | } |
3147 | 0 | AddTimeoutTerminateAfterToURL(osURL); |
3148 | |
|
3149 | 0 | poResponse = m_poDS->RunRequest(osURL.c_str(), osFilter.c_str()); |
3150 | |
|
3151 | 0 | json_object *poCount = json_ex_get_object_by_path(poResponse, "hits.count"); |
3152 | 0 | if (poCount == nullptr) |
3153 | 0 | { |
3154 | | // For _search request |
3155 | 0 | poCount = json_ex_get_object_by_path(poResponse, "hits.total"); |
3156 | 0 | if (poCount && json_object_get_type(poCount) == json_type_object) |
3157 | 0 | { |
3158 | | // Since ES 7.0 |
3159 | 0 | poCount = json_ex_get_object_by_path(poCount, "value"); |
3160 | 0 | } |
3161 | 0 | } |
3162 | 0 | if (poCount == nullptr) |
3163 | 0 | { |
3164 | | // For _count request |
3165 | 0 | poCount = json_ex_get_object_by_path(poResponse, "count"); |
3166 | 0 | } |
3167 | 0 | if (poCount == nullptr || json_object_get_type(poCount) != json_type_int) |
3168 | 0 | { |
3169 | 0 | json_object_put(poResponse); |
3170 | 0 | CPLDebug("ES", "Cannot find hits in GetFeatureCount() response. " |
3171 | 0 | "Falling back to slow implementation"); |
3172 | 0 | m_bUseSingleQueryParams = true; |
3173 | 0 | const auto nRet = OGRLayer::GetFeatureCount(bForce); |
3174 | 0 | m_bUseSingleQueryParams = false; |
3175 | 0 | return nRet; |
3176 | 0 | } |
3177 | | |
3178 | 0 | GIntBig nCount = json_object_get_int64(poCount); |
3179 | 0 | json_object_put(poResponse); |
3180 | 0 | return nCount; |
3181 | 0 | } |
3182 | | |
3183 | | /************************************************************************/ |
3184 | | /* GetValue() */ |
3185 | | /************************************************************************/ |
3186 | | |
3187 | | json_object *OGRElasticLayer::GetValue(int nFieldIdx, swq_expr_node *poValNode) |
3188 | 0 | { |
3189 | 0 | json_object *poVal = nullptr; |
3190 | 0 | if (poValNode->field_type == SWQ_FLOAT) |
3191 | 0 | poVal = json_object_new_double(poValNode->float_value); |
3192 | 0 | else if (poValNode->field_type == SWQ_INTEGER || |
3193 | 0 | poValNode->field_type == SWQ_INTEGER64) |
3194 | 0 | poVal = json_object_new_int64(poValNode->int_value); |
3195 | 0 | else if (poValNode->field_type == SWQ_STRING) |
3196 | 0 | poVal = json_object_new_string(poValNode->string_value); |
3197 | 0 | else if (poValNode->field_type == SWQ_TIMESTAMP) |
3198 | 0 | { |
3199 | 0 | int nYear = 0; |
3200 | 0 | int nMonth = 0; |
3201 | 0 | int nDay = 0; |
3202 | 0 | int nHour = 0; |
3203 | 0 | int nMinute = 0; |
3204 | 0 | float fSecond = 0; |
3205 | 0 | if (sscanf(poValNode->string_value, "%04d/%02d/%02d %02d:%02d:%f", |
3206 | 0 | &nYear, &nMonth, &nDay, &nHour, &nMinute, &fSecond) >= 3 || |
3207 | 0 | sscanf(poValNode->string_value, "%04d-%02d-%02dT%02d:%02d:%f", |
3208 | 0 | &nYear, &nMonth, &nDay, &nHour, &nMinute, &fSecond) >= 3) |
3209 | 0 | { |
3210 | 0 | OGRFieldType eType( |
3211 | 0 | m_poFeatureDefn->GetFieldDefn(nFieldIdx)->GetType()); |
3212 | 0 | if (eType == OFTDateTime) |
3213 | 0 | poVal = json_object_new_string( |
3214 | 0 | CPLSPrintf("%04d/%02d/%02d %02d:%02d:%02.03f", nYear, |
3215 | 0 | nMonth, nDay, nHour, nMinute, fSecond)); |
3216 | 0 | else if (eType == OFTDate) |
3217 | 0 | poVal = json_object_new_string( |
3218 | 0 | CPLSPrintf("%04d/%02d/%02d", nYear, nMonth, nDay)); |
3219 | 0 | else |
3220 | 0 | poVal = json_object_new_string( |
3221 | 0 | CPLSPrintf("%02d:%02d:%02.03f", nHour, nMinute, fSecond)); |
3222 | 0 | } |
3223 | 0 | else |
3224 | 0 | { |
3225 | 0 | return nullptr; |
3226 | 0 | } |
3227 | 0 | } |
3228 | 0 | else |
3229 | 0 | { |
3230 | 0 | CPLError(CE_Failure, CPLE_NotSupported, "Unhandled type: %d", |
3231 | 0 | poValNode->field_type); |
3232 | 0 | } |
3233 | 0 | return poVal; |
3234 | 0 | } |
3235 | | |
3236 | | /************************************************************************/ |
3237 | | /* OGRESGetFieldIndexFromSQL() */ |
3238 | | /************************************************************************/ |
3239 | | |
3240 | | static int OGRESGetFieldIndexFromSQL(const swq_expr_node *poNode) |
3241 | 0 | { |
3242 | 0 | if (poNode->eNodeType == SNT_COLUMN) |
3243 | 0 | return poNode->field_index; |
3244 | | |
3245 | 0 | if (poNode->eNodeType == SNT_OPERATION && poNode->nOperation == SWQ_CAST && |
3246 | 0 | poNode->nSubExprCount >= 1 && |
3247 | 0 | poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN) |
3248 | 0 | return poNode->papoSubExpr[0]->field_index; |
3249 | | |
3250 | 0 | return -1; |
3251 | 0 | } |
3252 | | |
3253 | | /************************************************************************/ |
3254 | | /* TranslateSQLToFilter() */ |
3255 | | /************************************************************************/ |
3256 | | |
3257 | | json_object *OGRElasticLayer::TranslateSQLToFilter(swq_expr_node *poNode) |
3258 | 0 | { |
3259 | 0 | if (poNode->eNodeType == SNT_OPERATION) |
3260 | 0 | { |
3261 | 0 | int nFieldIdx = 0; |
3262 | 0 | CPL_IGNORE_RET_VAL(nFieldIdx); // to make cppcheck happy |
3263 | 0 | if (poNode->nOperation == SWQ_AND && poNode->nSubExprCount == 2) |
3264 | 0 | { |
3265 | | // For AND, we can deal with a failure in one of the branch |
3266 | | // since client-side will do that extra filtering |
3267 | 0 | json_object *poFilter1 = |
3268 | 0 | TranslateSQLToFilter(poNode->papoSubExpr[0]); |
3269 | 0 | json_object *poFilter2 = |
3270 | 0 | TranslateSQLToFilter(poNode->papoSubExpr[1]); |
3271 | 0 | if (poFilter1 && poFilter2) |
3272 | 0 | { |
3273 | 0 | json_object *poRet = json_object_new_object(); |
3274 | 0 | json_object *poBool = json_object_new_object(); |
3275 | 0 | json_object_object_add(poRet, "bool", poBool); |
3276 | 0 | json_object *poMust = json_object_new_array(); |
3277 | 0 | json_object_object_add(poBool, "must", poMust); |
3278 | 0 | json_object_array_add(poMust, poFilter1); |
3279 | 0 | json_object_array_add(poMust, poFilter2); |
3280 | 0 | return poRet; |
3281 | 0 | } |
3282 | 0 | else if (poFilter1) |
3283 | 0 | return poFilter1; |
3284 | 0 | else |
3285 | 0 | return poFilter2; |
3286 | 0 | } |
3287 | 0 | else if (poNode->nOperation == SWQ_OR && poNode->nSubExprCount == 2) |
3288 | 0 | { |
3289 | 0 | json_object *poFilter1 = |
3290 | 0 | TranslateSQLToFilter(poNode->papoSubExpr[0]); |
3291 | 0 | json_object *poFilter2 = |
3292 | 0 | TranslateSQLToFilter(poNode->papoSubExpr[1]); |
3293 | 0 | if (poFilter1 && poFilter2) |
3294 | 0 | { |
3295 | 0 | json_object *poRet = json_object_new_object(); |
3296 | 0 | json_object *poBool = json_object_new_object(); |
3297 | 0 | json_object_object_add(poRet, "bool", poBool); |
3298 | 0 | json_object *poShould = json_object_new_array(); |
3299 | 0 | json_object_object_add(poBool, "should", poShould); |
3300 | 0 | json_object_array_add(poShould, poFilter1); |
3301 | 0 | json_object_array_add(poShould, poFilter2); |
3302 | 0 | return poRet; |
3303 | 0 | } |
3304 | 0 | else |
3305 | 0 | { |
3306 | 0 | json_object_put(poFilter1); |
3307 | 0 | json_object_put(poFilter2); |
3308 | 0 | return nullptr; |
3309 | 0 | } |
3310 | 0 | } |
3311 | 0 | else if (poNode->nOperation == SWQ_NOT && poNode->nSubExprCount == 1) |
3312 | 0 | { |
3313 | 0 | if (poNode->papoSubExpr[0]->eNodeType == SNT_OPERATION && |
3314 | 0 | poNode->papoSubExpr[0]->nOperation == SWQ_ISNULL && |
3315 | 0 | poNode->papoSubExpr[0]->nSubExprCount == 1 && |
3316 | 0 | poNode->papoSubExpr[0]->papoSubExpr[0]->field_index != 0 && |
3317 | 0 | poNode->papoSubExpr[0]->papoSubExpr[0]->field_index < |
3318 | 0 | m_poFeatureDefn->GetFieldCount()) |
3319 | 0 | { |
3320 | 0 | json_object *poRet = json_object_new_object(); |
3321 | 0 | json_object *poExists = json_object_new_object(); |
3322 | 0 | CPLString osFieldName(BuildPathFromArray( |
3323 | 0 | m_aaosFieldPaths |
3324 | 0 | [poNode->papoSubExpr[0]->papoSubExpr[0]->field_index])); |
3325 | 0 | json_object_object_add(poExists, "field", |
3326 | 0 | json_object_new_string(osFieldName)); |
3327 | 0 | json_object_object_add(poRet, "exists", poExists); |
3328 | 0 | return poRet; |
3329 | 0 | } |
3330 | 0 | else |
3331 | 0 | { |
3332 | 0 | json_object *poFilter = |
3333 | 0 | TranslateSQLToFilter(poNode->papoSubExpr[0]); |
3334 | 0 | if (poFilter) |
3335 | 0 | { |
3336 | 0 | json_object *poRet = json_object_new_object(); |
3337 | 0 | json_object *poBool = json_object_new_object(); |
3338 | 0 | json_object_object_add(poRet, "bool", poBool); |
3339 | 0 | json_object_object_add(poBool, "must_not", poFilter); |
3340 | 0 | return poRet; |
3341 | 0 | } |
3342 | 0 | else |
3343 | 0 | { |
3344 | 0 | return nullptr; |
3345 | 0 | } |
3346 | 0 | } |
3347 | 0 | } |
3348 | 0 | else if (poNode->nOperation == SWQ_ISNULL && |
3349 | 0 | poNode->nSubExprCount == 1 && |
3350 | 0 | (nFieldIdx = |
3351 | 0 | OGRESGetFieldIndexFromSQL(poNode->papoSubExpr[0])) > 0 && |
3352 | 0 | nFieldIdx < m_poFeatureDefn->GetFieldCount()) |
3353 | 0 | { |
3354 | 0 | json_object *poRet = json_object_new_object(); |
3355 | 0 | json_object *poExists = json_object_new_object(); |
3356 | 0 | CPLString osFieldName( |
3357 | 0 | BuildPathFromArray(m_aaosFieldPaths[nFieldIdx])); |
3358 | 0 | json_object_object_add(poExists, "field", |
3359 | 0 | json_object_new_string(osFieldName)); |
3360 | 0 | json_object *poBool = json_object_new_object(); |
3361 | 0 | json_object_object_add(poRet, "bool", poBool); |
3362 | 0 | json_object *poMustNot = json_object_new_object(); |
3363 | 0 | json_object_object_add(poMustNot, "exists", poExists); |
3364 | 0 | json_object_object_add(poBool, "must_not", poMustNot); |
3365 | 0 | return poRet; |
3366 | 0 | } |
3367 | 0 | else if (poNode->nOperation == SWQ_NE) |
3368 | 0 | { |
3369 | 0 | poNode->nOperation = SWQ_EQ; |
3370 | 0 | json_object *poFilter = TranslateSQLToFilter(poNode); |
3371 | 0 | poNode->nOperation = SWQ_NE; |
3372 | 0 | if (poFilter) |
3373 | 0 | { |
3374 | 0 | json_object *poRet = json_object_new_object(); |
3375 | 0 | json_object *poBool = json_object_new_object(); |
3376 | 0 | json_object_object_add(poRet, "bool", poBool); |
3377 | 0 | json_object_object_add(poBool, "must_not", poFilter); |
3378 | 0 | return poRet; |
3379 | 0 | } |
3380 | 0 | else |
3381 | 0 | { |
3382 | 0 | return nullptr; |
3383 | 0 | } |
3384 | 0 | } |
3385 | 0 | else if (poNode->nOperation == SWQ_EQ && poNode->nSubExprCount == 2 && |
3386 | 0 | poNode->papoSubExpr[1]->eNodeType == SNT_CONSTANT && |
3387 | 0 | (nFieldIdx = |
3388 | 0 | OGRESGetFieldIndexFromSQL(poNode->papoSubExpr[0])) >= 0 && |
3389 | 0 | nFieldIdx < m_poFeatureDefn->GetFieldCount()) |
3390 | 0 | { |
3391 | 0 | json_object *poVal = GetValue(nFieldIdx, poNode->papoSubExpr[1]); |
3392 | 0 | if (poVal == nullptr) |
3393 | 0 | { |
3394 | 0 | return nullptr; |
3395 | 0 | } |
3396 | 0 | json_object *poRet = json_object_new_object(); |
3397 | 0 | if (nFieldIdx == 0) |
3398 | 0 | { |
3399 | 0 | json_object *poIds = json_object_new_object(); |
3400 | 0 | json_object *poValues = json_object_new_array(); |
3401 | 0 | json_object_object_add(poIds, "values", poValues); |
3402 | 0 | json_object_array_add(poValues, poVal); |
3403 | 0 | json_object_object_add(poRet, "ids", poIds); |
3404 | 0 | } |
3405 | 0 | else |
3406 | 0 | { |
3407 | 0 | json_object *poTerm = json_object_new_object(); |
3408 | 0 | CPLString osPath( |
3409 | 0 | BuildPathFromArray(m_aaosFieldPaths[nFieldIdx])); |
3410 | 0 | bool bNotAnalyzed = true; |
3411 | 0 | if (poNode->papoSubExpr[1]->field_type == SWQ_STRING) |
3412 | 0 | { |
3413 | 0 | const char *pszFieldName = |
3414 | 0 | m_poFeatureDefn->GetFieldDefn(nFieldIdx)->GetNameRef(); |
3415 | 0 | bNotAnalyzed = CSLFindString(m_papszNotAnalyzedFields, |
3416 | 0 | pszFieldName) >= 0; |
3417 | 0 | if (!bNotAnalyzed) |
3418 | 0 | { |
3419 | 0 | if (CSLFindString(m_papszFieldsWithRawValue, |
3420 | 0 | pszFieldName) >= 0) |
3421 | 0 | { |
3422 | 0 | osPath += ".raw"; |
3423 | 0 | bNotAnalyzed = true; |
3424 | 0 | } |
3425 | 0 | else if (!m_bFilterMustBeClientSideEvaluated) |
3426 | 0 | { |
3427 | 0 | m_bFilterMustBeClientSideEvaluated = true; |
3428 | 0 | CPLDebug("ES", |
3429 | 0 | "Part or full filter will have to be " |
3430 | 0 | "evaluated on " |
3431 | 0 | "client side (equality test on a analyzed " |
3432 | 0 | "field)."); |
3433 | 0 | } |
3434 | 0 | } |
3435 | 0 | } |
3436 | 0 | json_object_object_add(poRet, bNotAnalyzed ? "term" : "match", |
3437 | 0 | poTerm); |
3438 | 0 | json_object_object_add(poTerm, osPath, poVal); |
3439 | |
|
3440 | 0 | if (!bNotAnalyzed && m_poDS->m_nMajorVersion < 2) |
3441 | 0 | { |
3442 | 0 | json_object *poNewRet = json_object_new_object(); |
3443 | 0 | json_object_object_add(poNewRet, "query", poRet); |
3444 | 0 | poRet = poNewRet; |
3445 | 0 | } |
3446 | 0 | } |
3447 | 0 | return poRet; |
3448 | 0 | } |
3449 | 0 | else if ((poNode->nOperation == SWQ_LT || |
3450 | 0 | poNode->nOperation == SWQ_LE || |
3451 | 0 | poNode->nOperation == SWQ_GT || |
3452 | 0 | poNode->nOperation == SWQ_GE) && |
3453 | 0 | poNode->nSubExprCount == 2 && |
3454 | 0 | poNode->papoSubExpr[1]->eNodeType == SNT_CONSTANT && |
3455 | 0 | (nFieldIdx = |
3456 | 0 | OGRESGetFieldIndexFromSQL(poNode->papoSubExpr[0])) > 0 && |
3457 | 0 | nFieldIdx < m_poFeatureDefn->GetFieldCount()) |
3458 | 0 | { |
3459 | 0 | json_object *poVal = GetValue(nFieldIdx, poNode->papoSubExpr[1]); |
3460 | 0 | if (poVal == nullptr) |
3461 | 0 | { |
3462 | 0 | return nullptr; |
3463 | 0 | } |
3464 | 0 | json_object *poRet = json_object_new_object(); |
3465 | 0 | json_object *poRange = json_object_new_object(); |
3466 | 0 | json_object_object_add(poRet, "range", poRange); |
3467 | 0 | json_object *poFieldConstraint = json_object_new_object(); |
3468 | 0 | CPLString osFieldName( |
3469 | 0 | BuildPathFromArray(m_aaosFieldPaths[nFieldIdx])); |
3470 | 0 | json_object_object_add(poRange, osFieldName, poFieldConstraint); |
3471 | 0 | const char *pszOp = (poNode->nOperation == SWQ_LT) ? "lt" |
3472 | 0 | : (poNode->nOperation == SWQ_LE) ? "lte" |
3473 | 0 | : (poNode->nOperation == SWQ_GT) |
3474 | 0 | ? "gt" |
3475 | 0 | : |
3476 | 0 | /*(poNode->nOperation == SWQ_GE) ?*/ "gte"; |
3477 | 0 | json_object_object_add(poFieldConstraint, pszOp, poVal); |
3478 | 0 | return poRet; |
3479 | 0 | } |
3480 | 0 | else if (poNode->nOperation == SWQ_BETWEEN && |
3481 | 0 | poNode->nSubExprCount == 3 && |
3482 | 0 | poNode->papoSubExpr[1]->eNodeType == SNT_CONSTANT && |
3483 | 0 | poNode->papoSubExpr[2]->eNodeType == SNT_CONSTANT && |
3484 | 0 | (nFieldIdx = |
3485 | 0 | OGRESGetFieldIndexFromSQL(poNode->papoSubExpr[0])) > 0 && |
3486 | 0 | nFieldIdx < m_poFeatureDefn->GetFieldCount()) |
3487 | 0 | { |
3488 | 0 | json_object *poVal1 = GetValue(nFieldIdx, poNode->papoSubExpr[1]); |
3489 | 0 | if (poVal1 == nullptr) |
3490 | 0 | { |
3491 | 0 | return nullptr; |
3492 | 0 | } |
3493 | 0 | json_object *poVal2 = GetValue(nFieldIdx, poNode->papoSubExpr[2]); |
3494 | 0 | if (poVal2 == nullptr) |
3495 | 0 | { |
3496 | 0 | json_object_put(poVal1); |
3497 | 0 | return nullptr; |
3498 | 0 | } |
3499 | | |
3500 | 0 | json_object *poRet = json_object_new_object(); |
3501 | 0 | json_object *poRange = json_object_new_object(); |
3502 | 0 | json_object_object_add(poRet, "range", poRange); |
3503 | 0 | json_object *poFieldConstraint = json_object_new_object(); |
3504 | 0 | CPLString osFieldName( |
3505 | 0 | BuildPathFromArray(m_aaosFieldPaths[nFieldIdx])); |
3506 | 0 | json_object_object_add(poRange, osFieldName, poFieldConstraint); |
3507 | 0 | json_object_object_add(poFieldConstraint, "gte", poVal1); |
3508 | 0 | json_object_object_add(poFieldConstraint, "lte", poVal2); |
3509 | 0 | return poRet; |
3510 | 0 | } |
3511 | 0 | else if (poNode->nOperation == SWQ_IN && poNode->nSubExprCount > 1 && |
3512 | 0 | (nFieldIdx = |
3513 | 0 | OGRESGetFieldIndexFromSQL(poNode->papoSubExpr[0])) >= 0 && |
3514 | 0 | nFieldIdx < m_poFeatureDefn->GetFieldCount()) |
3515 | 0 | { |
3516 | 0 | bool bAllConstant = true; |
3517 | 0 | for (int i = 1; i < poNode->nSubExprCount; i++) |
3518 | 0 | { |
3519 | 0 | if (poNode->papoSubExpr[i]->eNodeType != SNT_CONSTANT) |
3520 | 0 | { |
3521 | 0 | bAllConstant = false; |
3522 | 0 | break; |
3523 | 0 | } |
3524 | 0 | } |
3525 | 0 | if (bAllConstant) |
3526 | 0 | { |
3527 | 0 | json_object *poRet = json_object_new_object(); |
3528 | 0 | if (nFieldIdx == 0) |
3529 | 0 | { |
3530 | 0 | json_object *poIds = json_object_new_object(); |
3531 | 0 | json_object *poValues = json_object_new_array(); |
3532 | 0 | json_object_object_add(poIds, "values", poValues); |
3533 | 0 | json_object_object_add(poRet, "ids", poIds); |
3534 | 0 | for (int i = 1; i < poNode->nSubExprCount; i++) |
3535 | 0 | { |
3536 | 0 | json_object *poVal = |
3537 | 0 | GetValue(nFieldIdx, poNode->papoSubExpr[i]); |
3538 | 0 | if (poVal == nullptr) |
3539 | 0 | { |
3540 | 0 | json_object_put(poRet); |
3541 | 0 | return nullptr; |
3542 | 0 | } |
3543 | 0 | json_object_array_add(poValues, poVal); |
3544 | 0 | } |
3545 | 0 | } |
3546 | 0 | else |
3547 | 0 | { |
3548 | 0 | bool bNotAnalyzed = true; |
3549 | 0 | CPLString osPath( |
3550 | 0 | BuildPathFromArray(m_aaosFieldPaths[nFieldIdx])); |
3551 | 0 | if (poNode->papoSubExpr[1]->field_type == SWQ_STRING) |
3552 | 0 | { |
3553 | 0 | const char *pszFieldName = |
3554 | 0 | m_poFeatureDefn->GetFieldDefn(nFieldIdx) |
3555 | 0 | ->GetNameRef(); |
3556 | 0 | bNotAnalyzed = CSLFindString(m_papszNotAnalyzedFields, |
3557 | 0 | pszFieldName) >= 0; |
3558 | 0 | if (!bNotAnalyzed && |
3559 | 0 | CSLFindString(m_papszFieldsWithRawValue, |
3560 | 0 | pszFieldName) >= 0) |
3561 | 0 | { |
3562 | 0 | osPath += ".raw"; |
3563 | 0 | bNotAnalyzed = true; |
3564 | 0 | } |
3565 | |
|
3566 | 0 | if (!bNotAnalyzed && |
3567 | 0 | !m_bFilterMustBeClientSideEvaluated) |
3568 | 0 | { |
3569 | 0 | m_bFilterMustBeClientSideEvaluated = true; |
3570 | 0 | CPLDebug("ES", |
3571 | 0 | "Part or full filter will have to be " |
3572 | 0 | "evaluated on client side (IN test on a " |
3573 | 0 | "analyzed field)."); |
3574 | 0 | } |
3575 | 0 | } |
3576 | |
|
3577 | 0 | if (bNotAnalyzed) |
3578 | 0 | { |
3579 | 0 | json_object *poTerms = json_object_new_object(); |
3580 | 0 | json_object_object_add(poRet, "terms", poTerms); |
3581 | 0 | json_object *poTermsValues = json_object_new_array(); |
3582 | 0 | json_object_object_add(poTerms, osPath, poTermsValues); |
3583 | 0 | for (int i = 1; i < poNode->nSubExprCount; i++) |
3584 | 0 | { |
3585 | 0 | json_object *poVal = |
3586 | 0 | GetValue(nFieldIdx, poNode->papoSubExpr[i]); |
3587 | 0 | if (poVal == nullptr) |
3588 | 0 | { |
3589 | 0 | json_object_put(poRet); |
3590 | 0 | return nullptr; |
3591 | 0 | } |
3592 | 0 | json_object_array_add(poTermsValues, poVal); |
3593 | 0 | } |
3594 | 0 | } |
3595 | 0 | else |
3596 | 0 | { |
3597 | 0 | json_object *poBool = json_object_new_object(); |
3598 | 0 | json_object_object_add(poRet, "bool", poBool); |
3599 | 0 | json_object *poShould = json_object_new_array(); |
3600 | 0 | json_object_object_add(poBool, "should", poShould); |
3601 | 0 | for (int i = 1; i < poNode->nSubExprCount; i++) |
3602 | 0 | { |
3603 | 0 | json_object *poVal = |
3604 | 0 | GetValue(nFieldIdx, poNode->papoSubExpr[i]); |
3605 | 0 | if (poVal == nullptr) |
3606 | 0 | { |
3607 | 0 | json_object_put(poRet); |
3608 | 0 | return nullptr; |
3609 | 0 | } |
3610 | 0 | json_object *poShouldElt = json_object_new_object(); |
3611 | 0 | json_object *poMatch = json_object_new_object(); |
3612 | 0 | json_object_object_add(poShouldElt, "match", |
3613 | 0 | poMatch); |
3614 | 0 | json_object_object_add(poMatch, osPath, poVal); |
3615 | |
|
3616 | 0 | if (m_poDS->m_nMajorVersion < 2) |
3617 | 0 | { |
3618 | 0 | json_object *poNewShouldElt = |
3619 | 0 | json_object_new_object(); |
3620 | 0 | json_object_object_add(poNewShouldElt, "query", |
3621 | 0 | poShouldElt); |
3622 | 0 | poShouldElt = poNewShouldElt; |
3623 | 0 | } |
3624 | 0 | json_object_array_add(poShould, poShouldElt); |
3625 | 0 | } |
3626 | 0 | } |
3627 | 0 | } |
3628 | 0 | return poRet; |
3629 | 0 | } |
3630 | 0 | } |
3631 | 0 | else if ((poNode->nOperation == SWQ_LIKE || |
3632 | 0 | poNode->nOperation == |
3633 | 0 | SWQ_ILIKE) && // ES actual semantics doesn't match |
3634 | | // exactly either... |
3635 | 0 | poNode->nSubExprCount >= 2 && |
3636 | 0 | (nFieldIdx = |
3637 | 0 | OGRESGetFieldIndexFromSQL(poNode->papoSubExpr[0])) > 0 && |
3638 | 0 | nFieldIdx < m_poFeatureDefn->GetFieldCount()) |
3639 | 0 | { |
3640 | 0 | char chEscape = '\0'; |
3641 | 0 | if (poNode->nSubExprCount == 3) |
3642 | 0 | chEscape = poNode->papoSubExpr[2]->string_value[0]; |
3643 | 0 | const char *pszPattern = poNode->papoSubExpr[1]->string_value; |
3644 | 0 | const char *pszFieldName = |
3645 | 0 | m_poFeatureDefn->GetFieldDefn(nFieldIdx)->GetNameRef(); |
3646 | 0 | bool bNotAnalyzed = |
3647 | 0 | CSLFindString(m_papszNotAnalyzedFields, pszFieldName) >= 0; |
3648 | 0 | CPLString osPath(BuildPathFromArray(m_aaosFieldPaths[nFieldIdx])); |
3649 | 0 | if (!bNotAnalyzed && |
3650 | 0 | CSLFindString(m_papszFieldsWithRawValue, pszFieldName) >= 0) |
3651 | 0 | { |
3652 | 0 | osPath += ".raw"; |
3653 | 0 | bNotAnalyzed = true; |
3654 | 0 | } |
3655 | |
|
3656 | 0 | if (strchr(pszPattern, '*') || strchr(pszPattern, '?')) |
3657 | 0 | { |
3658 | 0 | CPLDebug("ES", "Cannot handle * or ? in LIKE pattern"); |
3659 | 0 | } |
3660 | 0 | else if (!bNotAnalyzed) |
3661 | 0 | { |
3662 | 0 | if (!m_bFilterMustBeClientSideEvaluated) |
3663 | 0 | { |
3664 | 0 | m_bFilterMustBeClientSideEvaluated = true; |
3665 | 0 | CPLDebug( |
3666 | 0 | "ES", |
3667 | 0 | "Part or full filter will have to be evaluated on " |
3668 | 0 | "client side (wildcard test on a analyzed field)."); |
3669 | 0 | } |
3670 | 0 | } |
3671 | 0 | else |
3672 | 0 | { |
3673 | 0 | CPLString osUnescaped; |
3674 | 0 | for (int i = 0; pszPattern[i] != '\0'; ++i) |
3675 | 0 | { |
3676 | 0 | if (chEscape == pszPattern[i]) |
3677 | 0 | { |
3678 | 0 | if (pszPattern[i + 1] == '\0') |
3679 | 0 | break; |
3680 | 0 | osUnescaped += pszPattern[i + 1]; |
3681 | 0 | i++; |
3682 | 0 | } |
3683 | 0 | else if (pszPattern[i] == '%') |
3684 | 0 | { |
3685 | 0 | osUnescaped += '*'; |
3686 | 0 | } |
3687 | 0 | else if (pszPattern[i] == '_') |
3688 | 0 | { |
3689 | 0 | osUnescaped += '?'; |
3690 | 0 | } |
3691 | 0 | else |
3692 | 0 | { |
3693 | 0 | osUnescaped += pszPattern[i]; |
3694 | 0 | } |
3695 | 0 | } |
3696 | 0 | json_object *poRet = json_object_new_object(); |
3697 | 0 | json_object *poWildcard = json_object_new_object(); |
3698 | 0 | json_object_object_add(poRet, "wildcard", poWildcard); |
3699 | 0 | json_object_object_add(poWildcard, osPath, |
3700 | 0 | json_object_new_string(osUnescaped)); |
3701 | 0 | return poRet; |
3702 | 0 | } |
3703 | 0 | } |
3704 | 0 | } |
3705 | | |
3706 | 0 | if (!m_bFilterMustBeClientSideEvaluated) |
3707 | 0 | { |
3708 | 0 | m_bFilterMustBeClientSideEvaluated = true; |
3709 | 0 | CPLDebug("ES", "Part or full filter will have to be evaluated on " |
3710 | 0 | "client side."); |
3711 | 0 | } |
3712 | 0 | return nullptr; |
3713 | 0 | } |
3714 | | |
3715 | | /************************************************************************/ |
3716 | | /* SetAttributeFilter() */ |
3717 | | /************************************************************************/ |
3718 | | |
3719 | | OGRErr OGRElasticLayer::SetAttributeFilter(const char *pszFilter) |
3720 | 0 | { |
3721 | 0 | m_bFilterMustBeClientSideEvaluated = false; |
3722 | 0 | if (pszFilter != nullptr && pszFilter[0] == '{') |
3723 | 0 | { |
3724 | 0 | if (!m_osESSearch.empty()) |
3725 | 0 | { |
3726 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
3727 | 0 | "Setting an Elasticsearch filter on a resulting layer " |
3728 | 0 | "is not supported"); |
3729 | 0 | return OGRERR_FAILURE; |
3730 | 0 | } |
3731 | 0 | OGRLayer::SetAttributeFilter(nullptr); |
3732 | 0 | m_osJSONFilter = pszFilter; |
3733 | 0 | return OGRERR_NONE; |
3734 | 0 | } |
3735 | 0 | else |
3736 | 0 | { |
3737 | 0 | m_osJSONFilter.clear(); |
3738 | 0 | json_object_put(m_poJSONFilter); |
3739 | 0 | m_poJSONFilter = nullptr; |
3740 | 0 | OGRErr eErr = OGRLayer::SetAttributeFilter(pszFilter); |
3741 | 0 | if (eErr == OGRERR_NONE && m_poAttrQuery != nullptr) |
3742 | 0 | { |
3743 | 0 | swq_expr_node *poNode = |
3744 | 0 | reinterpret_cast<swq_expr_node *>(m_poAttrQuery->GetSWQExpr()); |
3745 | 0 | m_poJSONFilter = TranslateSQLToFilter(poNode); |
3746 | 0 | } |
3747 | 0 | return eErr; |
3748 | 0 | } |
3749 | 0 | } |
3750 | | |
3751 | | /************************************************************************/ |
3752 | | /* ClampEnvelope() */ |
3753 | | /************************************************************************/ |
3754 | | |
3755 | | void OGRElasticLayer::ClampEnvelope(OGREnvelope &sEnvelope) |
3756 | 0 | { |
3757 | 0 | if (sEnvelope.MinX < -180) |
3758 | 0 | sEnvelope.MinX = -180; |
3759 | 0 | if (sEnvelope.MinX > 180) |
3760 | 0 | sEnvelope.MinX = 180; |
3761 | |
|
3762 | 0 | if (sEnvelope.MinY < -90) |
3763 | 0 | sEnvelope.MinY = -90; |
3764 | 0 | if (sEnvelope.MinY > 90) |
3765 | 0 | sEnvelope.MinY = 90; |
3766 | |
|
3767 | 0 | if (sEnvelope.MaxX > 180) |
3768 | 0 | sEnvelope.MaxX = 180; |
3769 | 0 | if (sEnvelope.MaxX < -180) |
3770 | 0 | sEnvelope.MaxX = -180; |
3771 | |
|
3772 | 0 | if (sEnvelope.MaxY > 90) |
3773 | 0 | sEnvelope.MaxY = 90; |
3774 | 0 | if (sEnvelope.MaxY < -90) |
3775 | 0 | sEnvelope.MaxY = -90; |
3776 | 0 | } |
3777 | | |
3778 | | /************************************************************************/ |
3779 | | /* ISetSpatialFilter() */ |
3780 | | /************************************************************************/ |
3781 | | |
3782 | | OGRErr OGRElasticLayer::ISetSpatialFilter(int iGeomField, |
3783 | | const OGRGeometry *poGeomIn) |
3784 | | |
3785 | 0 | { |
3786 | 0 | FinalizeFeatureDefn(); |
3787 | |
|
3788 | 0 | m_iGeomFieldFilter = iGeomField; |
3789 | |
|
3790 | 0 | InstallFilter(poGeomIn); |
3791 | |
|
3792 | 0 | json_object_put(m_poSpatialFilter); |
3793 | 0 | m_poSpatialFilter = nullptr; |
3794 | |
|
3795 | 0 | if (poGeomIn == nullptr) |
3796 | 0 | return OGRERR_NONE; |
3797 | | |
3798 | 0 | if (!m_osESSearch.empty()) |
3799 | 0 | { |
3800 | 0 | CPLError( |
3801 | 0 | CE_Failure, CPLE_AppDefined, |
3802 | 0 | "Setting a spatial filter on a resulting layer is not supported"); |
3803 | 0 | return OGRERR_FAILURE; |
3804 | 0 | } |
3805 | | |
3806 | 0 | OGREnvelope sEnvelope; |
3807 | 0 | poGeomIn->getEnvelope(&sEnvelope); |
3808 | 0 | ClampEnvelope(sEnvelope); |
3809 | |
|
3810 | 0 | if (sEnvelope.MinX == -180 && sEnvelope.MinY == -90 && |
3811 | 0 | sEnvelope.MaxX == 180 && sEnvelope.MaxY == 90) |
3812 | 0 | { |
3813 | 0 | return OGRERR_NONE; |
3814 | 0 | } |
3815 | | |
3816 | 0 | m_poSpatialFilter = json_object_new_object(); |
3817 | |
|
3818 | 0 | if (m_abIsGeoPoint[iGeomField]) |
3819 | 0 | { |
3820 | 0 | json_object *geo_bounding_box = json_object_new_object(); |
3821 | 0 | json_object_object_add(m_poSpatialFilter, "geo_bounding_box", |
3822 | 0 | geo_bounding_box); |
3823 | |
|
3824 | 0 | CPLString osPath = BuildPathFromArray(m_aaosGeomFieldPaths[iGeomField]); |
3825 | |
|
3826 | 0 | json_object *field = json_object_new_object(); |
3827 | 0 | json_object_object_add(geo_bounding_box, osPath.c_str(), field); |
3828 | |
|
3829 | 0 | json_object *top_left = json_object_new_object(); |
3830 | 0 | json_object_object_add(field, "top_left", top_left); |
3831 | 0 | json_object_object_add( |
3832 | 0 | top_left, "lat", |
3833 | 0 | json_object_new_double_with_precision(sEnvelope.MaxY, 6)); |
3834 | 0 | json_object_object_add( |
3835 | 0 | top_left, "lon", |
3836 | 0 | json_object_new_double_with_precision(sEnvelope.MinX, 6)); |
3837 | |
|
3838 | 0 | json_object *bottom_right = json_object_new_object(); |
3839 | 0 | json_object_object_add(field, "bottom_right", bottom_right); |
3840 | 0 | json_object_object_add( |
3841 | 0 | bottom_right, "lat", |
3842 | 0 | json_object_new_double_with_precision(sEnvelope.MinY, 6)); |
3843 | 0 | json_object_object_add( |
3844 | 0 | bottom_right, "lon", |
3845 | 0 | json_object_new_double_with_precision(sEnvelope.MaxX, 6)); |
3846 | 0 | } |
3847 | 0 | else |
3848 | 0 | { |
3849 | 0 | json_object *geo_shape = json_object_new_object(); |
3850 | 0 | json_object_object_add(m_poSpatialFilter, "geo_shape", geo_shape); |
3851 | |
|
3852 | 0 | CPLString osPath = BuildPathFromArray(m_aaosGeomFieldPaths[iGeomField]); |
3853 | |
|
3854 | 0 | json_object *field = json_object_new_object(); |
3855 | 0 | json_object_object_add(geo_shape, osPath.c_str(), field); |
3856 | |
|
3857 | 0 | json_object *shape = json_object_new_object(); |
3858 | 0 | json_object_object_add(field, "shape", shape); |
3859 | |
|
3860 | 0 | json_object_object_add(shape, "type", |
3861 | 0 | json_object_new_string("envelope")); |
3862 | |
|
3863 | 0 | json_object *coordinates = json_object_new_array(); |
3864 | 0 | json_object_object_add(shape, "coordinates", coordinates); |
3865 | |
|
3866 | 0 | json_object *top_left = json_object_new_array(); |
3867 | 0 | json_object_array_add( |
3868 | 0 | top_left, json_object_new_double_with_precision(sEnvelope.MinX, 6)); |
3869 | 0 | json_object_array_add( |
3870 | 0 | top_left, json_object_new_double_with_precision(sEnvelope.MaxY, 6)); |
3871 | 0 | json_object_array_add(coordinates, top_left); |
3872 | |
|
3873 | 0 | json_object *bottom_right = json_object_new_array(); |
3874 | 0 | json_object_array_add( |
3875 | 0 | bottom_right, |
3876 | 0 | json_object_new_double_with_precision(sEnvelope.MaxX, 6)); |
3877 | 0 | json_object_array_add( |
3878 | 0 | bottom_right, |
3879 | 0 | json_object_new_double_with_precision(sEnvelope.MinY, 6)); |
3880 | 0 | json_object_array_add(coordinates, bottom_right); |
3881 | 0 | } |
3882 | |
|
3883 | 0 | return OGRERR_NONE; |
3884 | 0 | } |
3885 | | |
3886 | | /************************************************************************/ |
3887 | | /* IGetExtent() */ |
3888 | | /************************************************************************/ |
3889 | | |
3890 | | OGRErr OGRElasticLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent, |
3891 | | bool bForce) |
3892 | 0 | { |
3893 | 0 | FinalizeFeatureDefn(); |
3894 | | |
3895 | | // geo_shape aggregation is only available since ES 7.8, but only with XPack |
3896 | | // for now |
3897 | 0 | if (!m_abIsGeoPoint[iGeomField] && |
3898 | 0 | !(m_poDS->m_nMajorVersion > 7 || |
3899 | 0 | (m_poDS->m_nMajorVersion == 7 && m_poDS->m_nMinorVersion >= 8))) |
3900 | 0 | { |
3901 | 0 | m_bUseSingleQueryParams = true; |
3902 | 0 | const auto eRet = OGRLayer::IGetExtent(iGeomField, psExtent, bForce); |
3903 | 0 | m_bUseSingleQueryParams = false; |
3904 | 0 | return eRet; |
3905 | 0 | } |
3906 | | |
3907 | 0 | CPLString osFilter = CPLSPrintf( |
3908 | 0 | "{ \"size\": 0, \"aggs\" : { \"bbox\" : { \"geo_bounds\" : { \"field\" " |
3909 | 0 | ": \"%s\" } } } }", |
3910 | 0 | BuildPathFromArray(m_aaosGeomFieldPaths[iGeomField]).c_str()); |
3911 | 0 | CPLString osURL = |
3912 | 0 | CPLSPrintf("%s/%s", m_poDS->GetURL(), m_osIndexName.c_str()); |
3913 | 0 | if (m_poDS->m_nMajorVersion < 7) |
3914 | 0 | osURL += CPLSPrintf("/%s", m_osMappingName.c_str()); |
3915 | 0 | osURL += "/_search?pretty"; |
3916 | 0 | AddTimeoutTerminateAfterToURL(osURL); |
3917 | |
|
3918 | 0 | CPLPushErrorHandler(CPLQuietErrorHandler); |
3919 | 0 | json_object *poResponse = |
3920 | 0 | m_poDS->RunRequest(osURL.c_str(), osFilter.c_str()); |
3921 | 0 | CPLPopErrorHandler(); |
3922 | 0 | if (poResponse == nullptr) |
3923 | 0 | { |
3924 | 0 | const char *pszLastErrorMsg = CPLGetLastErrorMsg(); |
3925 | 0 | if (!m_abIsGeoPoint[iGeomField] && |
3926 | 0 | strstr(pszLastErrorMsg, "Fielddata is not supported on field") != |
3927 | 0 | nullptr) |
3928 | 0 | { |
3929 | 0 | CPLDebug("ES", |
3930 | 0 | "geo_bounds aggregation failed, likely because of lack " |
3931 | 0 | "of XPack. Using client-side method"); |
3932 | 0 | CPLErrorReset(); |
3933 | 0 | } |
3934 | 0 | else |
3935 | 0 | { |
3936 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "%s", pszLastErrorMsg); |
3937 | 0 | } |
3938 | 0 | } |
3939 | |
|
3940 | 0 | json_object *poBounds = |
3941 | 0 | json_ex_get_object_by_path(poResponse, "aggregations.bbox.bounds"); |
3942 | 0 | json_object *poTopLeft = json_ex_get_object_by_path(poBounds, "top_left"); |
3943 | 0 | json_object *poBottomRight = |
3944 | 0 | json_ex_get_object_by_path(poBounds, "bottom_right"); |
3945 | 0 | json_object *poTopLeftLon = json_ex_get_object_by_path(poTopLeft, "lon"); |
3946 | 0 | json_object *poTopLeftLat = json_ex_get_object_by_path(poTopLeft, "lat"); |
3947 | 0 | json_object *poBottomRightLon = |
3948 | 0 | json_ex_get_object_by_path(poBottomRight, "lon"); |
3949 | 0 | json_object *poBottomRightLat = |
3950 | 0 | json_ex_get_object_by_path(poBottomRight, "lat"); |
3951 | |
|
3952 | 0 | OGRErr eErr; |
3953 | 0 | if (poTopLeftLon == nullptr || poTopLeftLat == nullptr || |
3954 | 0 | poBottomRightLon == nullptr || poBottomRightLat == nullptr) |
3955 | 0 | { |
3956 | 0 | m_bUseSingleQueryParams = true; |
3957 | 0 | const auto eRet = OGRLayer::IGetExtent(iGeomField, psExtent, bForce); |
3958 | 0 | m_bUseSingleQueryParams = false; |
3959 | 0 | return eRet; |
3960 | 0 | } |
3961 | 0 | else |
3962 | 0 | { |
3963 | 0 | double dfMinX = json_object_get_double(poTopLeftLon); |
3964 | 0 | double dfMaxY = json_object_get_double(poTopLeftLat); |
3965 | 0 | double dfMaxX = json_object_get_double(poBottomRightLon); |
3966 | 0 | double dfMinY = json_object_get_double(poBottomRightLat); |
3967 | |
|
3968 | 0 | psExtent->MinX = dfMinX; |
3969 | 0 | psExtent->MaxY = dfMaxY; |
3970 | 0 | psExtent->MaxX = dfMaxX; |
3971 | 0 | psExtent->MinY = dfMinY; |
3972 | |
|
3973 | 0 | eErr = OGRERR_NONE; |
3974 | 0 | } |
3975 | 0 | json_object_put(poResponse); |
3976 | |
|
3977 | 0 | return eErr; |
3978 | 0 | } |
3979 | | |
3980 | | /************************************************************************/ |
3981 | | /* GetDataset() */ |
3982 | | /************************************************************************/ |
3983 | | |
3984 | | GDALDataset *OGRElasticLayer::GetDataset() |
3985 | 0 | { |
3986 | 0 | return m_poDS; |
3987 | 0 | } |