diff --git a/CHANGELOG b/CHANGELOG index e9baa3c584..13c2dfef89 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -119,6 +119,14 @@ v2.5.0-alpha2 (2015-02-16) db.collection.ensureUniqueSkiplist(attributeName, { sparse: true }); db.collection.ensureUniqueSkiplist(attributeName1, attributeName2, { sparse: true }); + Note that in place of the above specialized index creation commands, it is recommended to use + the more general index creation command `ensureIndex`: + + ```js + db.collection.ensureIndex({ type: "hash", sparse: true, unique: true, fields: [ attributeName ] }); + db.collection.ensureIndex({ type: "skiplist", sparse: false, unique: false, fields: [ "a", "b" ] }); + ``` + When not explicitly set, the `sparse` attribute defaults to `false` for new indexes. This causes a change in behavior when creating a unique hash index without specifying the @@ -129,7 +137,18 @@ v2.5.0-alpha2 (2015-02-16) only be created sparse if sparsity is explicitly requested. Existing unique hash indexes from 2.4 or before will automatically be migrated so they are still sparse after the upgrade to 2.5. - Indexes other than hash and skiplist do not support sparsity. + Geo indexes are implicitly sparse, meaning documents without the indexed location attribute or + containing invalid location coordinate values will be excluded from the index automatically. This + is also a change when compared to pre-2.5 behavior, when documents with missing or invalid + coordinate values may have caused errors on insertion when the geo index' `unique` flag was set + and its `ignoreNull` flag was not. + + This was confusing and has been rectified in 2.5. The method `ensureGeoConstaint()` now does the + same as `ensureGeoIndex()`. Furthermore, the attributes `constraint`, `unique`, `ignoreNull` and + `sparse` flags are now completely ignored when creating geo indexes. + + The same is true for fulltext indexes. There is no need to specify non-uniqueness or sparsity for + geo or fulltext indexes. They will always be non-unique and sparse. As sparse indexes may exclude some documents, they cannot be used for every type of query. Sparse hash indexes cannot be used to find documents for which at least one of the indexed diff --git a/Documentation/Books/Users/NewFeatures/NewFeatures25.mdpp b/Documentation/Books/Users/NewFeatures/NewFeatures25.mdpp index 2369a68ad6..4eba47420f 100644 --- a/Documentation/Books/Users/NewFeatures/NewFeatures25.mdpp +++ b/Documentation/Books/Users/NewFeatures/NewFeatures25.mdpp @@ -52,7 +52,16 @@ db.collection.ensureUniqueSkiplist(attributeName, { sparse: true }); db.collection.ensureUniqueSkiplist(attributeName1, attributeName2, { sparse: true }); ``` -When not explicitly set, the `sparse` attribute defaults to `false` for new indexes. +Note that in place of the above specialized index creation commands, it is recommended to use +the more general index creation command `ensureIndex`: + +```js +db.collection.ensureIndex({ type: "hash", sparse: true, unique: true, fields: [ attributeName ] }); +db.collection.ensureIndex({ type: "skiplist", sparse: false, unique: false, fields: [ "a", "b" ] }); +``` + +When not explicitly set, the `sparse` attribute defaults to `false` for new hash or +skiplist indexes. This causes a change in behavior when creating a unique hash index without specifying the sparse flag: in 2.4, unique hash indexes were implicitly sparse, always excluding `null` values. @@ -61,8 +70,18 @@ hash indexes nor skiplists in 2.4. This implicit sparsity of unique hash indexes an inconsistency, and therefore the behavior was cleaned up in 2.5. As of 2.5, indexes will only be created sparse if sparsity is explicitly requested. Existing unique hash indexes from 2.4 or before will automatically be migrated so they are still sparse after the upgrade to 2.5. - -Other indexes than hash and skiplist do not support sparsity. + +Geo indexes are implicitly sparse, meaning documents without the indexed location attribute or +containing invalid location coordinate values will be excluded from the index automatically. This +is also a change when compared to pre-2.5 behavior, when documents with missing or invalid +coordinate values may have caused errors on insertion when the geo index' `unique` flag was set +and its `ignoreNull` flag was not. This was confusing and has been rectified in 2.5. The method +`ensureGeoConstaint()` now does the same as `ensureGeoIndex()`. Furthermore, the attributes +`constraint`, `unique`, `ignoreNull` and `sparse` flags are now completely ignored when creating +geo indexes. + +The same is true for fulltext indexes. There is no need to specify non-uniqueness or sparsity for +geo or fulltext indexes. As sparse indexes may exclude some documents, they cannot be used for every type of query. Sparse hash indexes cannot be used to find documents for which at least one of the indexed diff --git a/Documentation/Books/Users/Upgrading/UpgradingChanges25.mdpp b/Documentation/Books/Users/Upgrading/UpgradingChanges25.mdpp index a2adca0c11..0ac52b449b 100644 --- a/Documentation/Books/Users/Upgrading/UpgradingChanges25.mdpp +++ b/Documentation/Books/Users/Upgrading/UpgradingChanges25.mdpp @@ -8,8 +8,8 @@ upgrading to ArangoDB 2.5, and adjust any client programs if necessary. !SUBSECTION Sparse indexes -Hash indexes and skiplist indexes can now be created sparse. When not explicitly set, the -`sparse` attribute defaults to `false` for new indexes. +Hash indexes and skiplist indexes can now be created in a sparse variant. +When not explicitly set, the `sparse` attribute defaults to `false` for new indexes. This causes a change in behavior when creating a unique hash index without specifying the sparse flag. The unique hash index will be created in a non-sparse variant in ArangoDB 2.5. @@ -19,14 +19,29 @@ from the index. There was no option to control this behavior, and sparsity was n for non-unique hash indexes nor skiplists in 2.4. This implicit sparsity of just unique hash indexes was considered an inconsistency, and therefore the behavior was cleaned up in 2.5. -As of 2.5, indexes will only be created sparse if sparsity is explicitly requested. This may -require a change in index-creating client code, but only if the client code creates unique hash -indexes and if they are still intended to be sparse. In this case, the client code should -explicitly set the `sparse` flag to `true` when creating a unique hash index. +As of 2.5, hash and skiplist indexes will only be created sparse if sparsity is explicitly requested. +This may require a change in index-creating client code, but only if the client code creates +unique hash indexes and if they are still intended to be sparse. In this case, the client code +should explicitly set the `sparse` flag to `true` when creating a unique hash index. Existing unique hash indexes from 2.4 or before will automatically be migrated so they are still -sparse after the upgrade to 2.5. For the indexes, the `sparse` attribute will be populated -automatically with a value of `true`. +sparse after the upgrade to 2.5. For these indexes, the `sparse` attribute will be populated +automatically with a value of `true`. + +Geo indexes are implicitly sparse, meaning documents without the indexed location attribute or +containing invalid location coordinate values will be excluded from the index automatically. This +is also a change when compared to pre-2.5 behavior, when documents with missing or invalid +coordinate values may have caused errors on insertion when the geo index' `unique` flag was set +and its `ignoreNull` flag was not. + +This was confusing and has been rectified in 2.5. The method `ensureGeoConstaint()` now does the +same as `ensureGeoIndex()`. Furthermore, the attributes `constraint`, `unique`, `ignoreNull` and +`sparse` flags are now completely ignored when creating geo indexes. Client index creation code +therefore does not need to set the `ignoreNull` or `constraint` attributes when creating a geo +index. + +The same is true for fulltext indexes. There is no need to specify non-uniqueness or sparsity for +geo or fulltext indexes. They will always be non-unique and sparse. !SECTION Deprecated features diff --git a/UnitTests/HttpInterface/api-index-spec.rb b/UnitTests/HttpInterface/api-index-spec.rb index 73575f98bb..869914f03d 100644 --- a/UnitTests/HttpInterface/api-index-spec.rb +++ b/UnitTests/HttpInterface/api-index-spec.rb @@ -179,6 +179,8 @@ describe ArangoDB do doc.parsed_response['fields'].should eq([ "a" ]) doc.parsed_response['isNewlyCreated'].should eq(true) doc.parsed_response['unique'].should eq(false) + doc.parsed_response['sparse'].should eq(true) + doc.parsed_response['ignoreNull'].should eq(true) doc = ArangoDB.log_post("#{prefix}-create-old-geo", cmd, :body => body) @@ -192,6 +194,8 @@ describe ArangoDB do doc.parsed_response['fields'].should eq([ "a" ]) doc.parsed_response['isNewlyCreated'].should eq(false) doc.parsed_response['unique'].should eq(false) + doc.parsed_response['sparse'].should eq(true) + doc.parsed_response['ignoreNull'].should eq(true) end it "creating geo index with location" do @@ -209,6 +213,8 @@ describe ArangoDB do doc.parsed_response['fields'].should eq([ "b" ]) doc.parsed_response['isNewlyCreated'].should eq(true) doc.parsed_response['unique'].should eq(false) + doc.parsed_response['sparse'].should eq(true) + doc.parsed_response['ignoreNull'].should eq(true) end it "creating geo index with location and geo-json = true" do @@ -226,6 +232,8 @@ describe ArangoDB do doc.parsed_response['fields'].should eq([ "c" ]) doc.parsed_response['isNewlyCreated'].should eq(true) doc.parsed_response['unique'].should eq(false) + doc.parsed_response['sparse'].should eq(true) + doc.parsed_response['ignoreNull'].should eq(true) end it "creating geo index with location and geo-json = false" do @@ -243,6 +251,8 @@ describe ArangoDB do doc.parsed_response['fields'].should eq([ "d" ]) doc.parsed_response['isNewlyCreated'].should eq(true) doc.parsed_response['unique'].should eq(false) + doc.parsed_response['sparse'].should eq(true) + doc.parsed_response['ignoreNull'].should eq(true) end it "creating geo index with latitude and longitude" do @@ -259,6 +269,8 @@ describe ArangoDB do doc.parsed_response['fields'].should eq([ "e", "f" ]) doc.parsed_response['isNewlyCreated'].should eq(true) doc.parsed_response['unique'].should eq(false) + doc.parsed_response['sparse'].should eq(true) + doc.parsed_response['ignoreNull'].should eq(true) end it "creating geo index with constraint" do @@ -274,8 +286,10 @@ describe ArangoDB do doc.parsed_response['type'].should eq("geo1") doc.parsed_response['geoJson'].should eq(true) doc.parsed_response['fields'].should eq([ "c" ]) - doc.parsed_response['unique'].should eq(true) + doc.parsed_response['unique'].should eq(false) doc.parsed_response['isNewlyCreated'].should eq(true) + doc.parsed_response['sparse'].should eq(true) + doc.parsed_response['ignoreNull'].should eq(true) end it "creating geo index with constraint" do @@ -290,8 +304,10 @@ describe ArangoDB do doc.parsed_response['id'].should match(@reFull) doc.parsed_response['type'].should eq("geo2") doc.parsed_response['fields'].should eq([ "c", "d" ]) - doc.parsed_response['unique'].should eq(true) + doc.parsed_response['unique'].should eq(false) doc.parsed_response['isNewlyCreated'].should eq(true) + doc.parsed_response['sparse'].should eq(true) + doc.parsed_response['ignoreNull'].should eq(true) end end @@ -349,6 +365,8 @@ describe ArangoDB do doc.parsed_response['type'].should eq("geo1") doc.parsed_response['geoJson'].should eq(false) doc.parsed_response['fields'].should eq([ "a" ]) + doc.parsed_response['sparse'].should eq(true) + doc.parsed_response['ignoreNull'].should eq(true) end end diff --git a/arangod/GeoIndex/geo-index.cpp b/arangod/GeoIndex/geo-index.cpp index ddce23ade9..3e757b422c 100644 --- a/arangod/GeoIndex/geo-index.cpp +++ b/arangod/GeoIndex/geo-index.cpp @@ -258,11 +258,10 @@ static TRI_json_t* JsonGeo1Index (TRI_index_t const* idx) { TRI_Insert3ObjectJson(TRI_CORE_MEM_ZONE, json, "geoJson", TRI_CreateBooleanJson(TRI_CORE_MEM_ZONE, geo->_geoJson)); - // "constraint" and "unique" are identical for geo indexes. - // we return "constraint" just for downwards-compatibility - TRI_Insert3ObjectJson(TRI_CORE_MEM_ZONE, json, "constraint", TRI_CreateBooleanJson(TRI_CORE_MEM_ZONE, idx->_unique)); - - TRI_Insert3ObjectJson(TRI_CORE_MEM_ZONE, json, "ignoreNull", TRI_CreateBooleanJson(TRI_CORE_MEM_ZONE, idx->_ignoreNull)); + // "constraint" is always false as of ArangoDB 2.5 + TRI_Insert3ObjectJson(TRI_CORE_MEM_ZONE, json, "constraint", TRI_CreateBooleanJson(TRI_CORE_MEM_ZONE, false)); + // "ignoreNull" is always true as of ArangoDB 2.5 + TRI_Insert3ObjectJson(TRI_CORE_MEM_ZONE, json, "ignoreNull", TRI_CreateBooleanJson(TRI_CORE_MEM_ZONE, true)); TRI_json_t* fields = TRI_CreateArrayJson(TRI_CORE_MEM_ZONE, 1); TRI_PushBack3ArrayJson(TRI_CORE_MEM_ZONE, fields, TRI_CreateStringCopyJson(TRI_CORE_MEM_ZONE, location, strlen(location))); @@ -300,11 +299,10 @@ static TRI_json_t* JsonGeo2Index (TRI_index_t const* idx) { return nullptr; } - // "constraint" and "unique" are identical for geo indexes. - // we return "constraint" just for downwards-compatibility - TRI_Insert3ObjectJson(TRI_CORE_MEM_ZONE, json, "constraint", TRI_CreateBooleanJson(TRI_CORE_MEM_ZONE, idx->_unique)); - - TRI_Insert3ObjectJson(TRI_CORE_MEM_ZONE, json, "ignoreNull", TRI_CreateBooleanJson(TRI_CORE_MEM_ZONE, geo->base._ignoreNull)); + // "constraint" is always false as of ArangoDB 2.5 + TRI_Insert3ObjectJson(TRI_CORE_MEM_ZONE, json, "constraint", TRI_CreateBooleanJson(TRI_CORE_MEM_ZONE, false)); + // "ignoreNull" is always true as of ArangoDB 2.5 + TRI_Insert3ObjectJson(TRI_CORE_MEM_ZONE, json, "ignoreNull", TRI_CreateBooleanJson(TRI_CORE_MEM_ZONE, true)); TRI_json_t* fields = TRI_CreateArrayJson(TRI_CORE_MEM_ZONE, 2); TRI_PushBack3ArrayJson(TRI_CORE_MEM_ZONE, fields, TRI_CreateStringCopyJson(TRI_CORE_MEM_ZONE, latitude, strlen(latitude))); @@ -351,23 +349,12 @@ static int InsertGeoIndex (TRI_index_t* idx, } if (! ok) { - if (idx->_unique) { - if (idx->_ignoreNull && missing) { - return TRI_ERROR_NO_ERROR; - } - else { - return TRI_set_errno(TRI_ERROR_ARANGO_GEO_INDEX_VIOLATED); - } - } - else { - return TRI_ERROR_NO_ERROR; - } + return TRI_ERROR_NO_ERROR; } // and insert into index gc.latitude = latitude; gc.longitude = longitude; - gc.data = CONST_CAST(doc); res = GeoIndex_insert(geo->_geoIndex, &gc); @@ -380,13 +367,8 @@ static int InsertGeoIndex (TRI_index_t* idx, return TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY); } else if (res == -3) { - if (idx->_unique) { - LOG_DEBUG("illegal geo-coordinates, ignoring entry"); - return TRI_set_errno(TRI_ERROR_ARANGO_GEO_INDEX_VIOLATED); - } - else { - return TRI_ERROR_NO_ERROR; - } + LOG_DEBUG("illegal geo-coordinates, ignoring entry"); + return TRI_ERROR_NO_ERROR; } else if (res < 0) { return TRI_set_errno(TRI_ERROR_INTERNAL); @@ -428,7 +410,6 @@ static int RemoveGeoIndex (TRI_index_t* idx, if (ok) { gc.latitude = latitude; gc.longitude = longitude; - gc.data = CONST_CAST(doc); // ignore non-existing elements in geo-index @@ -450,9 +431,7 @@ TRI_index_t* TRI_CreateGeo1Index (TRI_document_collection_t* document, TRI_idx_iid_t iid, char const* locationName, TRI_shape_pid_t location, - bool geoJson, - bool unique, - bool ignoreNull) { + bool geoJson) { char* ln; TRI_geo_index_t* geo = static_cast(TRI_Allocate(TRI_CORE_MEM_ZONE, sizeof(TRI_geo_index_t), false)); @@ -460,9 +439,7 @@ TRI_index_t* TRI_CreateGeo1Index (TRI_document_collection_t* document, TRI_InitVectorString(&idx->_fields, TRI_CORE_MEM_ZONE); - TRI_InitIndex(idx, iid, TRI_IDX_TYPE_GEO1_INDEX, document, false, unique); - idx->_ignoreNull = ignoreNull; - + TRI_InitIndex(idx, iid, TRI_IDX_TYPE_GEO1_INDEX, document, true, false); idx->memory = MemoryGeoIndex; idx->json = JsonGeo1Index; idx->insert = InsertGeoIndex; @@ -498,9 +475,7 @@ TRI_index_t* TRI_CreateGeo2Index (TRI_document_collection_t* document, char const* latitudeName, TRI_shape_pid_t latitude, char const* longitudeName, - TRI_shape_pid_t longitude, - bool unique, - bool ignoreNull) { + TRI_shape_pid_t longitude) { char* lat; char* lon; @@ -509,9 +484,7 @@ TRI_index_t* TRI_CreateGeo2Index (TRI_document_collection_t* document, TRI_InitVectorString(&idx->_fields, TRI_CORE_MEM_ZONE); - TRI_InitIndex(idx, iid, TRI_IDX_TYPE_GEO2_INDEX, document, false, unique); - idx->_ignoreNull = ignoreNull; - + TRI_InitIndex(idx, iid, TRI_IDX_TYPE_GEO2_INDEX, document, true, false); idx->memory = MemoryGeoIndex; idx->json = JsonGeo2Index; idx->insert = InsertGeoIndex; diff --git a/arangod/GeoIndex/geo-index.h b/arangod/GeoIndex/geo-index.h index 94846950e1..82b8d1c441 100644 --- a/arangod/GeoIndex/geo-index.h +++ b/arangod/GeoIndex/geo-index.h @@ -50,8 +50,6 @@ TRI_index_t* TRI_CreateGeo1Index (struct TRI_document_collection_t*, TRI_idx_iid_t, char const*, TRI_shape_pid_t, - bool, - bool, bool); //////////////////////////////////////////////////////////////////////////////// @@ -63,9 +61,7 @@ TRI_index_t* TRI_CreateGeo2Index (struct TRI_document_collection_t*, char const*, TRI_shape_pid_t , char const*, - TRI_shape_pid_t, - bool, - bool); + TRI_shape_pid_t); //////////////////////////////////////////////////////////////////////////////// /// @brief frees the memory allocated, but does not free the pointer diff --git a/arangod/V8Server/v8-vocindex.cpp b/arangod/V8Server/v8-vocindex.cpp index 1bf608d9c3..748386c5d8 100644 --- a/arangod/V8Server/v8-vocindex.cpp +++ b/arangod/V8Server/v8-vocindex.cpp @@ -219,28 +219,10 @@ static int ProcessIndexSparseFlag (v8::Isolate* isolate, static int ProcessIndexUniqueFlag (v8::Isolate* isolate, v8::Handle const obj, - TRI_json_t* json, - bool fillConstraint = false) { + TRI_json_t* json) { v8::HandleScope scope(isolate); bool unique = ExtractBoolFlag(isolate, obj, TRI_V8_ASCII_STRING("unique"), false); TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, json, "unique", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, unique)); - if (fillConstraint) { - TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, json, "constraint", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, unique)); - } - - return TRI_ERROR_NO_ERROR; -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief process the ignoreNull flag and add it to the json -//////////////////////////////////////////////////////////////////////////////// - -static int ProcessIndexIgnoreNullFlag (v8::Isolate* isolate, - v8::Handle const obj, - TRI_json_t* json) { - v8::HandleScope scope(isolate); - bool ignoreNull = ExtractBoolFlag(isolate, obj, TRI_V8_ASCII_STRING("ignoreNull"), false); - TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, json, "ignoreNull", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, ignoreNull)); return TRI_ERROR_NO_ERROR; } @@ -254,8 +236,12 @@ static int EnhanceJsonIndexGeo1 (v8::Isolate* isolate, TRI_json_t* json, bool create) { int res = ProcessIndexFields(isolate, obj, json, 1, create); - ProcessIndexUniqueFlag(isolate, obj, json, true); - ProcessIndexIgnoreNullFlag(isolate, obj, json); + if (ServerState::instance()->isCoordinator()) { + TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, json, "ignoreNull", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, true)); + TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, json, "constraint", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, false)); + } + TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, json, "sparse", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, true)); + TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, json, "unique", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, false)); ProcessIndexGeoJsonFlag(isolate, obj, json); return res; } @@ -269,8 +255,13 @@ static int EnhanceJsonIndexGeo2 (v8::Isolate* isolate, TRI_json_t* json, bool create) { int res = ProcessIndexFields(isolate, obj, json, 2, create); - ProcessIndexUniqueFlag(isolate, obj, json, true); - ProcessIndexIgnoreNullFlag(isolate, obj, json); + if (ServerState::instance()->isCoordinator()) { + TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, json, "ignoreNull", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, true)); + TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, json, "constraint", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, false)); + } + TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, json, "sparse", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, true)); + TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, json, "unique", TRI_CreateBooleanJson(TRI_UNKNOWN_MEM_ZONE, false)); + ProcessIndexGeoJsonFlag(isolate, obj, json); return res; } @@ -642,12 +633,6 @@ static void EnsureIndexLocal (const v8::FunctionCallbackInfo& args, TRI_ASSERT(attributes._length == 1); - bool ignoreNull = false; - TRI_json_t* value = TRI_LookupObjectJson(json, "ignoreNull"); - if (TRI_IsBooleanJson(value)) { - ignoreNull = value->_value._boolean; - } - bool geoJson = false; value = TRI_LookupObjectJson(json, "geoJson"); if (TRI_IsBooleanJson(value)) { @@ -659,16 +644,12 @@ static void EnsureIndexLocal (const v8::FunctionCallbackInfo& args, iid, (char const*) TRI_AtVectorPointer(&attributes, 0), geoJson, - unique, - ignoreNull, &created); } else { idx = TRI_LookupGeoIndex1DocumentCollection(document, (char const*) TRI_AtVectorPointer(&attributes, 0), - geoJson, - unique, - ignoreNull); + geoJson); } break; } @@ -682,27 +663,17 @@ static void EnsureIndexLocal (const v8::FunctionCallbackInfo& args, TRI_ASSERT(attributes._length == 2); - bool ignoreNull = false; - TRI_json_t const* value = TRI_LookupObjectJson(json, "ignoreNull"); - if (TRI_IsBooleanJson(value)) { - ignoreNull = value->_value._boolean; - } - if (create) { idx = TRI_EnsureGeoIndex2DocumentCollection(document, iid, (char const*) TRI_AtVectorPointer(&attributes, 0), (char const*) TRI_AtVectorPointer(&attributes, 1), - unique, - ignoreNull, &created); } else { idx = TRI_LookupGeoIndex2DocumentCollection(document, (char const*) TRI_AtVectorPointer(&attributes, 0), - (char const*) TRI_AtVectorPointer(&attributes, 1), - unique, - ignoreNull); + (char const*) TRI_AtVectorPointer(&attributes, 1)); } break; } diff --git a/arangod/VocBase/document-collection.cpp b/arangod/VocBase/document-collection.cpp index 8c44cbb5e6..104a179846 100644 --- a/arangod/VocBase/document-collection.cpp +++ b/arangod/VocBase/document-collection.cpp @@ -3710,8 +3710,6 @@ static TRI_index_t* CreateGeoIndexDocumentCollection (TRI_document_collection_t* char const* latitude, char const* longitude, bool geoJson, - bool unique, - bool ignoreNull, TRI_idx_iid_t iid, bool* created) { TRI_index_t* idx; @@ -3757,10 +3755,10 @@ static TRI_index_t* CreateGeoIndexDocumentCollection (TRI_document_collection_t* // check, if we know the index if (location != nullptr) { - idx = TRI_LookupGeoIndex1DocumentCollection(document, location, geoJson, unique, ignoreNull); + idx = TRI_LookupGeoIndex1DocumentCollection(document, location, geoJson); } else if (longitude != nullptr && latitude != nullptr) { - idx = TRI_LookupGeoIndex2DocumentCollection(document, latitude, longitude, unique, ignoreNull); + idx = TRI_LookupGeoIndex2DocumentCollection(document, latitude, longitude); } else { TRI_set_errno(TRI_ERROR_INTERNAL); @@ -3780,14 +3778,14 @@ static TRI_index_t* CreateGeoIndexDocumentCollection (TRI_document_collection_t* // create a new index if (location != nullptr) { - idx = TRI_CreateGeo1Index(document, iid, location, loc, geoJson, unique, ignoreNull); + idx = TRI_CreateGeo1Index(document, iid, location, loc, geoJson); LOG_TRACE("created geo-index for location '%s': %ld", location, (unsigned long) loc); } else if (longitude != nullptr && latitude != nullptr) { - idx = TRI_CreateGeo2Index(document, iid, latitude, lat, longitude, lon, unique, ignoreNull); + idx = TRI_CreateGeo2Index(document, iid, latitude, lat, longitude, lon); LOG_TRACE("created geo-index for location '%s': %ld, %ld", location, @@ -3837,8 +3835,6 @@ static int GeoIndexFromJson (TRI_document_collection_t* document, TRI_json_t* type; TRI_json_t* bv; TRI_json_t* fld; - bool unique; - bool ignoreNull; char const* typeStr; size_t fieldCount; @@ -3861,31 +3857,6 @@ static int GeoIndexFromJson (TRI_document_collection_t* document, return TRI_errno(); } - // extract unique - unique = false; - // first try "unique" attribute - bv = TRI_LookupObjectJson(definition, "unique"); - - if (bv != nullptr && bv->_type == TRI_JSON_BOOLEAN) { - unique = bv->_value._boolean; - } - else { - // then "constraint" - bv = TRI_LookupObjectJson(definition, "constraint"); - - if (TRI_IsBooleanJson(bv)) { - unique = bv->_value._boolean; - } - } - - // extract ignore null - ignoreNull = false; - bv = TRI_LookupObjectJson(definition, "ignoreNull"); - - if (TRI_IsBooleanJson(bv)) { - ignoreNull = bv->_value._boolean; - } - // list style if (TRI_EqualString(typeStr, "geo1")) { bool geoJson; @@ -3907,8 +3878,6 @@ static int GeoIndexFromJson (TRI_document_collection_t* document, nullptr, nullptr, geoJson, - unique, - ignoreNull, iid, nullptr); @@ -3937,8 +3906,6 @@ static int GeoIndexFromJson (TRI_document_collection_t* document, lat->_value._string.data, lon->_value._string.data, false, - unique, - ignoreNull, iid, nullptr); @@ -3973,9 +3940,7 @@ static int GeoIndexFromJson (TRI_document_collection_t* document, TRI_index_t* TRI_LookupGeoIndex1DocumentCollection (TRI_document_collection_t* document, char const* location, - bool geoJson, - bool unique, - bool ignoreNull) { + bool geoJson) { TRI_shaper_t* shaper = document->getShaper(); // ONLY IN INDEX, PROTECTED by RUNTIME TRI_shape_pid_t loc = shaper->lookupAttributePathByName(shaper, location); @@ -3993,11 +3958,8 @@ TRI_index_t* TRI_LookupGeoIndex1DocumentCollection (TRI_document_collection_t* d TRI_geo_index_t* geo = (TRI_geo_index_t*) idx; if (geo->_location != 0 && geo->_location == loc && - geo->_geoJson == geoJson && - idx->_unique == unique) { - if (! unique || geo->base._ignoreNull == ignoreNull) { - return idx; - } + geo->_geoJson == geoJson) { + return idx; } } } @@ -4011,9 +3973,7 @@ TRI_index_t* TRI_LookupGeoIndex1DocumentCollection (TRI_document_collection_t* d TRI_index_t* TRI_LookupGeoIndex2DocumentCollection (TRI_document_collection_t* document, char const* latitude, - char const* longitude, - bool unique, - bool ignoreNull) { + char const* longitude) { TRI_shaper_t* shaper = document->getShaper(); // ONLY IN INDEX, PROTECTED by RUNTIME TRI_shape_pid_t lat = shaper->lookupAttributePathByName(shaper, latitude); @@ -4034,11 +3994,8 @@ TRI_index_t* TRI_LookupGeoIndex2DocumentCollection (TRI_document_collection_t* d if (geo->_latitude != 0 && geo->_longitude != 0 && geo->_latitude == lat && - geo->_longitude == lon && - idx->_unique == unique) { - if (! unique || geo->base._ignoreNull == ignoreNull) { - return idx; - } + geo->_longitude == lon) { + return idx; } } } @@ -4054,8 +4011,6 @@ TRI_index_t* TRI_EnsureGeoIndex1DocumentCollection (TRI_document_collection_t* d TRI_idx_iid_t iid, char const* location, bool geoJson, - bool unique, - bool ignoreNull, bool* created) { TRI_ReadLockReadWriteLock(&document->_vocbase->_inventoryLock); @@ -4065,7 +4020,7 @@ TRI_index_t* TRI_EnsureGeoIndex1DocumentCollection (TRI_document_collection_t* d TRI_WRITE_LOCK_DOCUMENTS_INDEXES_PRIMARY_COLLECTION(document); - TRI_index_t* idx = CreateGeoIndexDocumentCollection(document, location, nullptr, nullptr, geoJson, unique, ignoreNull, iid, created); + TRI_index_t* idx = CreateGeoIndexDocumentCollection(document, location, nullptr, nullptr, geoJson, iid, created); if (idx != nullptr) { if (created) { @@ -4096,8 +4051,6 @@ TRI_index_t* TRI_EnsureGeoIndex2DocumentCollection (TRI_document_collection_t* d TRI_idx_iid_t iid, char const* latitude, char const* longitude, - bool unique, - bool ignoreNull, bool* created) { TRI_ReadLockReadWriteLock(&document->_vocbase->_inventoryLock); @@ -4107,7 +4060,7 @@ TRI_index_t* TRI_EnsureGeoIndex2DocumentCollection (TRI_document_collection_t* d TRI_WRITE_LOCK_DOCUMENTS_INDEXES_PRIMARY_COLLECTION(document); - TRI_index_t* idx = CreateGeoIndexDocumentCollection(document, nullptr, latitude, longitude, false, unique, ignoreNull, iid, created); + TRI_index_t* idx = CreateGeoIndexDocumentCollection(document, nullptr, latitude, longitude, false, iid, created); if (idx != nullptr) { if (created) { diff --git a/arangod/VocBase/document-collection.h b/arangod/VocBase/document-collection.h index 5ca895dab0..b99d8bca71 100644 --- a/arangod/VocBase/document-collection.h +++ b/arangod/VocBase/document-collection.h @@ -818,8 +818,6 @@ TRI_index_t* TRI_EnsureCapConstraintDocumentCollection (TRI_document_collection_ struct TRI_index_s* TRI_LookupGeoIndex1DocumentCollection (TRI_document_collection_t*, char const*, - bool, - bool, bool); //////////////////////////////////////////////////////////////////////////////// @@ -830,9 +828,7 @@ struct TRI_index_s* TRI_LookupGeoIndex1DocumentCollection (TRI_document_collecti struct TRI_index_s* TRI_LookupGeoIndex2DocumentCollection (TRI_document_collection_t*, char const*, - char const*, - bool, - bool); + char const*); //////////////////////////////////////////////////////////////////////////////// /// @brief ensures that a geo index exists, list style @@ -842,8 +838,6 @@ struct TRI_index_s* TRI_EnsureGeoIndex1DocumentCollection (TRI_document_collecti TRI_idx_iid_t, char const*, bool, - bool, - bool, bool*); //////////////////////////////////////////////////////////////////////////////// @@ -854,8 +848,6 @@ struct TRI_index_s* TRI_EnsureGeoIndex2DocumentCollection (TRI_document_collecti TRI_idx_iid_t, char const*, char const*, - bool, - bool, bool*); // ----------------------------------------------------------------------------- diff --git a/arangod/VocBase/index.cpp b/arangod/VocBase/index.cpp index 14e8daca11..991b7331a5 100644 --- a/arangod/VocBase/index.cpp +++ b/arangod/VocBase/index.cpp @@ -436,11 +436,11 @@ TRI_json_t* TRI_JsonIndex (TRI_memory_zone_t* zone, TRI_Insert3ObjectJson(zone, json, "type", TRI_CreateStringCopyJson(zone, TRI_TypeNameIndex(idx->_type), strlen(TRI_TypeNameIndex(idx->_type)))); TRI_Insert3ObjectJson(zone, json, "unique", TRI_CreateBooleanJson(zone, idx->_unique)); - if (idx->_type == TRI_IDX_TYPE_HASH_INDEX || - idx->_type == TRI_IDX_TYPE_SKIPLIST_INDEX) { + if (idx->_type != TRI_IDX_TYPE_CAP_CONSTRAINT) { // only show sparse flag for these index types, as it can't be set on others TRI_Insert3ObjectJson(zone, json, "sparse", TRI_CreateBooleanJson(zone, idx->_sparse)); } + if (idx->_hasSelectivityEstimate) { TRI_Insert3ObjectJson(zone, json, "selectivityEstimate", TRI_CreateNumberJson(zone, idx->selectivityEstimate(idx))); } @@ -1783,7 +1783,7 @@ TRI_index_t* TRI_CreateFulltextIndex (TRI_document_collection_t* document, idx = &fulltextIndex->base; - TRI_InitIndex(idx, iid, TRI_IDX_TYPE_FULLTEXT_INDEX, document, false, false); + TRI_InitIndex(idx, iid, TRI_IDX_TYPE_FULLTEXT_INDEX, document, true, false); idx->memory = MemoryFulltextIndex; idx->json = JsonFulltextIndex; @@ -1874,20 +1874,6 @@ bool IndexComparator (TRI_json_t const* lhs, return false; } } - value = TRI_LookupObjectJson(lhs, "ignoreNull"); - if (TRI_IsBooleanJson(value)) { - if (! TRI_CheckSameValueJson(value, TRI_LookupObjectJson(rhs, "ignoreNull"))) { - return false; - } - } - } - else if (type == TRI_IDX_TYPE_GEO2_INDEX) { - value = TRI_LookupObjectJson(lhs, "ignoreNull"); - if (TRI_IsBooleanJson(value)) { - if (! TRI_CheckSameValueJson(value, TRI_LookupObjectJson(rhs, "ignoreNull"))) { - return false; - } - } } else if (type == TRI_IDX_TYPE_FULLTEXT_INDEX) { // minLength diff --git a/arangod/VocBase/index.h b/arangod/VocBase/index.h index 9485fca3e8..4db23553bd 100644 --- a/arangod/VocBase/index.h +++ b/arangod/VocBase/index.h @@ -99,7 +99,6 @@ typedef struct TRI_index_s { TRI_vector_string_t _fields; bool _unique; - bool _ignoreNull; bool _sparse; bool _hasSelectivityEstimate; diff --git a/js/actions/api-index.js b/js/actions/api-index.js index a577b4958c..42904cf935 100644 --- a/js/actions/api-index.js +++ b/js/actions/api-index.js @@ -314,22 +314,14 @@ function get_api_index (req, res) { /// followed by latitude. This corresponds to the format described in /// http://geojson.org/geojson-spec.html#positions /// -/// - *constraint*: If *constraint* is *true*, then a geo-spatial -/// constraint is created. The constraint is a non-unique variant of the index. -/// **Note**: It is also possible to set the *unique* attribute instead of -/// the *constraint* attribute. -/// -/// - *ignoreNull*: If a geo-spatial constraint is created and -/// *ignoreNull* is true, then documents with a null in *location* or at -/// least one null in *latitude* or *longitude* are ignored. -/// -/// **Note**: Unique indexes on non-shard keys are not supported in a cluster. +/// Geo indexes are always sparse, meaning that documents that do not contain +/// the index attributes or have non-numeric values in the index attributes +/// will not be indexed. /// /// @RESTRETURNCODES /// /// @RESTRETURNCODE{200} -/// If the index already exists, then a *HTTP 200* is -/// returned. +/// If the index already exists, then a *HTTP 200* is returned. /// /// @RESTRETURNCODE{201} /// If the index does not already exist and could be created, then a *HTTP 201* @@ -348,7 +340,10 @@ function get_api_index (req, res) { /// db._create(cn); /// /// var url = "/_api/index?collection=" + cn; -/// var body = '{ "type": "geo", "fields" : [ "b" ] }'; +/// var body = { +/// type: "geo", +/// fields : [ "b" ] +/// }; /// /// var response = logCurlRequest('POST', url, body); /// @@ -365,7 +360,10 @@ function get_api_index (req, res) { /// db._create(cn); /// /// var url = "/_api/index?collection=" + cn; -/// var body = '{ "type": "geo", "fields" : [ "e", "f" ] }'; +/// var body = { +/// type: "geo", +/// fields: [ "e", "f" ] +/// }; /// /// var response = logCurlRequest('POST', url, body); /// @@ -443,7 +441,11 @@ function get_api_index (req, res) { /// db._create(cn); /// /// var url = "/_api/index?collection=" + cn; -/// var body = '{ "type": "hash", "unique" : true, "fields" : [ "a", "b" ] }'; +/// var body = { +/// type: "hash", +/// unique: true, +/// fields : [ "a", "b" ] +/// }; /// /// var response = logCurlRequest('POST', url, body); /// @@ -460,7 +462,11 @@ function get_api_index (req, res) { /// db._create(cn); /// /// var url = "/_api/index?collection=" + cn; -/// var body = '{ "type": "hash", "unique" : false, "fields" : [ "a", "b" ] }'; +/// var body = { +/// type: "hash", +/// unique: false, +/// fields: [ "a", "b" ] +/// }; /// /// var response = logCurlRequest('POST', url, body); /// @@ -477,7 +483,12 @@ function get_api_index (req, res) { /// db._create(cn); /// /// var url = "/_api/index?collection=" + cn; -/// var body = '{ "type": "hash", "unique" : false, "sparse" : true, "fields" : [ "a" ] }'; +/// var body = { +/// type: "hash", +/// unique: false, +/// sparse: true, +/// fields: [ "a" ] +/// }; /// /// var response = logCurlRequest('POST', url, body); /// @@ -556,7 +567,11 @@ function get_api_index (req, res) { /// db._create(cn); /// /// var url = "/_api/index?collection=" + cn; -/// var body = '{ "type": "skiplist", "unique" : false, "fields" : [ "a", "b" ] }'; +/// var body = { +/// type: "skiplist", +/// unique: false, +/// fields: [ "a", "b" ] +/// }; /// /// var response = logCurlRequest('POST', url, body); /// @@ -573,7 +588,12 @@ function get_api_index (req, res) { /// db._create(cn); /// /// var url = "/_api/index?collection=" + cn; -/// var body = '{ "type": "skiplist", "unique" : false, "sparse" : true, "fields" : [ "a" ] }'; +/// var body = { +/// type: "skiplist", +/// unique: false, +/// sparse: true, +/// fields: [ "a" ] +/// }; /// /// var response = logCurlRequest('POST', url, body); /// @@ -636,7 +656,10 @@ function get_api_index (req, res) { /// db._create(cn); /// /// var url = "/_api/index?collection=" + cn; -/// var body = '{ "type" : "fulltext", "fields" : [ "text" ] }'; +/// var body = { +/// type: "fulltext", +/// fields: [ "text" ] +/// }; /// /// var response = logCurlRequest('POST', url, body); /// @@ -687,6 +710,7 @@ function get_api_index (req, res) { /// /// **Note**: The following index types do not support uniqueness, and using /// the *unique* attribute with these types may lead to an error: +/// /// - cap constraints /// - fulltext indexes /// @@ -742,20 +766,9 @@ function post_api_index (req, res) { body.collection = name; } - // fill "unique" attribute from "constraint" attribute to be downward-compatible - // with old geo index API - if (body.hasOwnProperty("constraint") && ! body.hasOwnProperty("unique")) { - body.unique = body.constraint; - } - // create the index var index = collection.ensureIndex(body); - if (index.isNewlyCreated) { - actions.resultOk(req, res, actions.HTTP_CREATED, index); - } - else { - actions.resultOk(req, res, actions.HTTP_OK, index); - } + actions.resultOk(req, res, index.isNewlyCreated ? actions.HTTP_CREATED : actions.HTTP_OK, index); } //////////////////////////////////////////////////////////////////////////////// diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/arango-collection.js b/js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/arango-collection.js index 1b277ebedf..b03446ddde 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/arango-collection.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/modules/org/arangodb/arango-collection.js @@ -709,23 +709,21 @@ ArangoCollection.prototype.ensureGeoIndex = function (lat, lon) { body = { type : "geo", fields : [ lat ], - geoJson : lon, - constraint : false + geoJson : lon }; } else if (lon === undefined) { body = { type : "geo", fields : [ lat ], - geoJson : false, - constraint : false + geoJson : false }; } else { body = { type : "geo", fields : [ lat, lon ], - constraint : false + geoJson: false }; } @@ -738,55 +736,11 @@ ArangoCollection.prototype.ensureGeoIndex = function (lat, lon) { //////////////////////////////////////////////////////////////////////////////// /// @brief ensures a geo constraint +/// since ArangoDB 2.5, this is just a redirection to ensureGeoIndex //////////////////////////////////////////////////////////////////////////////// -ArangoCollection.prototype.ensureGeoConstraint = function (lat, lon, ignoreNull) { - var body; - - // only two parameter - if (ignoreNull === undefined) { - ignoreNull = lon; - - if (typeof ignoreNull !== "boolean") { - throw "usage: ensureGeoConstraint(, , )" - + " or ensureGeoConstraint(, , )"; - } - - body = { - type : "geo", - fields : [ lat ], - geoJson : false, - constraint : true, - ignoreNull : ignoreNull - }; - } - - // three parameter - else { - if (typeof lon === "boolean") { - body = { - type : "geo", - fields : [ lat ], - geoJson : lon, - constraint : true, - ignoreNull : ignoreNull - }; - } - else { - body = { - type : "geo", - fields : [ lat, lon ], - constraint : true, - ignoreNull : ignoreNull - }; - } - } - - var requestResult = this._database._connection.POST(this._indexurl(), JSON.stringify(body)); - - arangosh.checkRequestResult(requestResult); - - return requestResult; +ArangoCollection.prototype.ensureGeoConstraint = function (lat, lon) { + return this.ensureGeoIndex(lat, lon); }; //////////////////////////////////////////////////////////////////////////////// diff --git a/js/client/modules/org/arangodb/arango-collection.js b/js/client/modules/org/arangodb/arango-collection.js index dacfaafa86..7db6b93d6c 100644 --- a/js/client/modules/org/arangodb/arango-collection.js +++ b/js/client/modules/org/arangodb/arango-collection.js @@ -708,23 +708,21 @@ ArangoCollection.prototype.ensureGeoIndex = function (lat, lon) { body = { type : "geo", fields : [ lat ], - geoJson : lon, - constraint : false + geoJson : lon }; } else if (lon === undefined) { body = { type : "geo", fields : [ lat ], - geoJson : false, - constraint : false + geoJson : false }; } else { body = { type : "geo", fields : [ lat, lon ], - constraint : false + geoJson: false }; } @@ -737,55 +735,11 @@ ArangoCollection.prototype.ensureGeoIndex = function (lat, lon) { //////////////////////////////////////////////////////////////////////////////// /// @brief ensures a geo constraint +/// since ArangoDB 2.5, this is just a redirection to ensureGeoIndex //////////////////////////////////////////////////////////////////////////////// -ArangoCollection.prototype.ensureGeoConstraint = function (lat, lon, ignoreNull) { - var body; - - // only two parameter - if (ignoreNull === undefined) { - ignoreNull = lon; - - if (typeof ignoreNull !== "boolean") { - throw "usage: ensureGeoConstraint(, , )" - + " or ensureGeoConstraint(, , )"; - } - - body = { - type : "geo", - fields : [ lat ], - geoJson : false, - constraint : true, - ignoreNull : ignoreNull - }; - } - - // three parameter - else { - if (typeof lon === "boolean") { - body = { - type : "geo", - fields : [ lat ], - geoJson : lon, - constraint : true, - ignoreNull : ignoreNull - }; - } - else { - body = { - type : "geo", - fields : [ lat, lon ], - constraint : true, - ignoreNull : ignoreNull - }; - } - } - - var requestResult = this._database._connection.POST(this._indexurl(), JSON.stringify(body)); - - arangosh.checkRequestResult(requestResult); - - return requestResult; +ArangoCollection.prototype.ensureGeoConstraint = function (lat, lon) { + return this.ensureGeoIndex(lat, lon); }; //////////////////////////////////////////////////////////////////////////////// diff --git a/js/common/tests/shell-index-ensure.js b/js/common/tests/shell-index-ensure.js index 0aa5c03187..2f3bfc495a 100644 --- a/js/common/tests/shell-index-ensure.js +++ b/js/common/tests/shell-index-ensure.js @@ -547,7 +547,8 @@ function ensureIndexSuite() { assertEqual("geo1", idx.type); assertFalse(idx.unique); assertEqual([ "a" ], idx.fields); - assertFalse(idx.ignoreNull); + assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertFalse(idx.geoJson); res = collection.getIndexes()[collection.getIndexes().length - 1]; @@ -555,7 +556,8 @@ function ensureIndexSuite() { assertEqual("geo1", res.type); assertFalse(res.unique); assertEqual([ "a" ], res.fields); - assertFalse(res.ignoreNull); + assertTrue(res.ignoreNull); + assertTrue(res.sparse); assertFalse(res.geoJson); assertEqual(idx.id, res.id); @@ -572,17 +574,19 @@ function ensureIndexSuite() { var idx = collection.ensureIndex({ type: "geo2", fields: [ "a", "b" ], unique: true }); assertEqual("geo2", idx.type); - assertTrue(idx.unique); + assertFalse(idx.unique); assertEqual([ "a", "b" ], idx.fields); - assertFalse(idx.ignoreNull); + assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertFalse(idx.geoJson); res = collection.getIndexes()[collection.getIndexes().length - 1]; assertEqual("geo2", res.type); - assertTrue(res.unique); + assertFalse(res.unique); assertEqual([ "a", "b" ], res.fields); - assertFalse(res.ignoreNull); + assertTrue(res.ignoreNull); + assertTrue(res.ignoreNull); assertFalse(res.geoJson); assertEqual(idx.id, res.id); diff --git a/js/common/tests/shell-index-geo.js b/js/common/tests/shell-index-geo.js index 1616532014..5efcf36e05 100644 --- a/js/common/tests/shell-index-geo.js +++ b/js/common/tests/shell-index-geo.js @@ -198,8 +198,9 @@ function GeoIndexCreationSuite() { assertNotEqual(0, id); assertEqual("geo1", idx.type); - assertTrue(idx.constraint); - assertFalse(idx.ignoreNull); + assertFalse(idx.constraint); + assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertFalse(idx.geoJson); assertEqual(["loc"], idx.fields); assertTrue(idx.isNewlyCreated); @@ -208,8 +209,9 @@ function GeoIndexCreationSuite() { assertEqual(id, idx.id); assertEqual("geo1", idx.type); - assertTrue(idx.constraint); - assertFalse(idx.ignoreNull); + assertFalse(idx.constraint); + assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertFalse(idx.geoJson); assertEqual(["loc"], idx.fields); assertFalse(idx.isNewlyCreated); @@ -218,8 +220,9 @@ function GeoIndexCreationSuite() { assertNotEqual(id, idx.id); assertEqual("geo1", idx.type); - assertTrue(idx.constraint); - assertFalse(idx.ignoreNull); + assertFalse(idx.constraint); + assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertTrue(idx.geoJson); assertEqual(["loc"], idx.fields); assertTrue(idx.isNewlyCreated); @@ -230,8 +233,9 @@ function GeoIndexCreationSuite() { assertNotEqual(id, idx.id); assertEqual("geo1", idx.type); - assertTrue(idx.constraint); - assertFalse(idx.ignoreNull); + assertFalse(idx.constraint); + assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertTrue(idx.geoJson); assertEqual(["loc"], idx.fields); assertFalse(idx.isNewlyCreated); @@ -247,8 +251,9 @@ function GeoIndexCreationSuite() { assertNotEqual(0, id); assertEqual("geo1", idx.type); - assertTrue(idx.constraint); - assertFalse(idx.ignoreNull); + assertFalse(idx.constraint); + assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertTrue(idx.geoJson); assertEqual(["loc"], idx.fields); assertTrue(idx.isNewlyCreated); @@ -257,8 +262,9 @@ function GeoIndexCreationSuite() { assertEqual(id, idx.id); assertEqual("geo1", idx.type); - assertTrue(idx.constraint); - assertFalse(idx.ignoreNull); + assertFalse(idx.constraint); + assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertTrue(idx.geoJson); assertEqual(["loc"], idx.fields); assertFalse(idx.isNewlyCreated); @@ -267,8 +273,9 @@ function GeoIndexCreationSuite() { assertNotEqual(id, idx.id); assertEqual("geo1", idx.type); - assertTrue(idx.constraint); - assertFalse(idx.ignoreNull); + assertFalse(idx.constraint); + assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertFalse(idx.geoJson); assertEqual(["loc"], idx.fields); assertTrue(idx.isNewlyCreated); @@ -279,8 +286,9 @@ function GeoIndexCreationSuite() { assertNotEqual(id, idx.id); assertEqual("geo1", idx.type); - assertTrue(idx.constraint); - assertFalse(idx.ignoreNull); + assertFalse(idx.constraint); + assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertFalse(idx.geoJson); assertEqual(["loc"], idx.fields); assertFalse(idx.isNewlyCreated); @@ -296,8 +304,9 @@ function GeoIndexCreationSuite() { assertNotEqual(0, id); assertEqual("geo2", idx.type); - assertTrue(idx.constraint); - assertFalse(idx.ignoreNull); + assertFalse(idx.constraint); + assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertEqual(["lat", "lon"], idx.fields); assertTrue(idx.isNewlyCreated); @@ -305,8 +314,9 @@ function GeoIndexCreationSuite() { assertEqual(id, idx.id); assertEqual("geo2", idx.type); - assertTrue(idx.constraint); - assertFalse(idx.ignoreNull); + assertFalse(idx.constraint); + assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertEqual(["lat", "lon"], idx.fields); assertFalse(idx.isNewlyCreated); @@ -316,8 +326,9 @@ function GeoIndexCreationSuite() { assertEqual(id, idx.id); assertEqual("geo2", idx.type); - assertTrue(idx.constraint); - assertFalse(idx.ignoreNull); + assertFalse(idx.constraint); + assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertEqual(["lat", "lon"], idx.fields); assertFalse(idx.isNewlyCreated); }, @@ -332,9 +343,10 @@ function GeoIndexCreationSuite() { assertNotEqual(0, id); assertEqual("geo1", idx.type); - assertTrue(idx.constraint); + assertFalse(idx.constraint); assertTrue(idx.ignoreNull); - assertFalse(idx.geoJson); + assertTrue(idx.sparse); + assertTrue(idx.geoJson); assertEqual(["loc"], idx.fields); assertTrue(idx.isNewlyCreated); @@ -342,40 +354,22 @@ function GeoIndexCreationSuite() { assertEqual(id, idx.id); assertEqual("geo1", idx.type); - assertTrue(idx.constraint); - assertTrue(idx.ignoreNull); - assertFalse(idx.geoJson); - assertEqual(["loc"], idx.fields); - assertFalse(idx.isNewlyCreated); - - idx = collection.ensureGeoConstraint("loc", true, true); - - assertNotEqual(id, idx.id); - assertEqual("geo1", idx.type); - assertTrue(idx.constraint); + assertFalse(idx.constraint); assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertTrue(idx.geoJson); assertEqual(["loc"], idx.fields); - assertTrue(idx.isNewlyCreated); + assertFalse(idx.isNewlyCreated); collection.unload(); - idx = collection.ensureGeoConstraint("loc", true, true); - - assertNotEqual(id, idx.id); - assertEqual("geo1", idx.type); - assertTrue(idx.constraint); - assertTrue(idx.ignoreNull); - assertTrue(idx.geoJson); - assertEqual(["loc"], idx.fields); - assertFalse(idx.isNewlyCreated); - idx = collection.ensureGeoConstraint("loc", false); assertNotEqual(id, idx.id); assertEqual("geo1", idx.type); - assertTrue(idx.constraint); - assertFalse(idx.ignoreNull); + assertFalse(idx.constraint); + assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertFalse(idx.geoJson); assertEqual(["loc"], idx.fields); assertTrue(idx.isNewlyCreated); @@ -386,8 +380,9 @@ function GeoIndexCreationSuite() { assertNotEqual(id, idx.id); assertEqual("geo1", idx.type); - assertTrue(idx.constraint); - assertFalse(idx.ignoreNull); + assertFalse(idx.constraint); + assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertFalse(idx.geoJson); assertEqual(["loc"], idx.fields); assertFalse(idx.isNewlyCreated); @@ -403,8 +398,9 @@ function GeoIndexCreationSuite() { assertNotEqual(0, id); assertEqual("geo1", idx.type); - assertTrue(idx.constraint); + assertFalse(idx.constraint); assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertTrue(idx.geoJson); assertEqual(["loc"], idx.fields); assertTrue(idx.isNewlyCreated); @@ -413,8 +409,9 @@ function GeoIndexCreationSuite() { assertEqual(id, idx.id); assertEqual("geo1", idx.type); - assertTrue(idx.constraint); + assertFalse(idx.constraint); assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertTrue(idx.geoJson); assertEqual(["loc"], idx.fields); assertFalse(idx.isNewlyCreated); @@ -423,8 +420,9 @@ function GeoIndexCreationSuite() { assertNotEqual(id, idx.id); assertEqual("geo1", idx.type); - assertTrue(idx.constraint); + assertFalse(idx.constraint); assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertFalse(idx.geoJson); assertEqual(["loc"], idx.fields); assertTrue(idx.isNewlyCreated); @@ -435,8 +433,9 @@ function GeoIndexCreationSuite() { assertNotEqual(id, idx.id); assertEqual("geo1", idx.type); - assertTrue(idx.constraint); + assertFalse(idx.constraint); assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertFalse(idx.geoJson); assertEqual(["loc"], idx.fields); assertFalse(idx.isNewlyCreated); @@ -452,8 +451,9 @@ function GeoIndexCreationSuite() { assertNotEqual(0, id); assertEqual("geo2", idx.type); - assertTrue(idx.constraint); + assertFalse(idx.constraint); assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertEqual(["lat", "lon"], idx.fields); assertTrue(idx.isNewlyCreated); @@ -461,8 +461,9 @@ function GeoIndexCreationSuite() { assertEqual(id, idx.id); assertEqual("geo2", idx.type); - assertTrue(idx.constraint); + assertFalse(idx.constraint); assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertEqual(["lat", "lon"], idx.fields); assertFalse(idx.isNewlyCreated); @@ -472,28 +473,9 @@ function GeoIndexCreationSuite() { assertEqual(id, idx.id); assertEqual("geo2", idx.type); - assertTrue(idx.constraint); + assertFalse(idx.constraint); assertTrue(idx.ignoreNull); - assertEqual(["lat", "lon"], idx.fields); - assertFalse(idx.isNewlyCreated); - - idx = collection.ensureGeoConstraint("lat", "lon", false); - - assertNotEqual(id, idx.id); - assertEqual("geo2", idx.type); - assertTrue(idx.constraint); - assertFalse(idx.ignoreNull); - assertEqual(["lat", "lon"], idx.fields); - assertTrue(idx.isNewlyCreated); - - collection.unload(); - - idx = collection.ensureGeoConstraint("lat", "lon", false); - - assertNotEqual(id, idx.id); - assertEqual("geo2", idx.type); - assertTrue(idx.constraint); - assertFalse(idx.ignoreNull); + assertTrue(idx.sparse); assertEqual(["lat", "lon"], idx.fields); assertFalse(idx.isNewlyCreated); } @@ -562,300 +544,8 @@ function GeoIndexErrorHandlingSuite() { collection.replace(d4, { loc : [ -100, -200 ] }); assertEqual(1, collection.near(0,0).toArray().length); - }, - -//////////////////////////////////////////////////////////////////////////////// -/// @brief test: error handling index -//////////////////////////////////////////////////////////////////////////////// - - testErrorHandlingConstraintList : function () { - collection.ensureGeoConstraint("loc", false); - - var d1 = collection.save({ loc : [ 0, 0 ] }); - - try { - collection.save({ a : 1 }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.save({ loc : null }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.save({ loc : [0] }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.save({ loc : [ -100, -200 ] }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - assertEqual(1, collection.near(0,0).toArray().length); - - try { - collection.replace(d1._id, { a : 1 }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.replace(d1._id, { loc : null }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.replace(d1._id, { loc : [0] }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.replace(d1._id, { loc : [ -100, -200 ] }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - assertEqual(1, collection.near(0,0).toArray().length); - }, - -//////////////////////////////////////////////////////////////////////////////// -/// @brief test: error handling index -//////////////////////////////////////////////////////////////////////////////// - - testErrorHandlingConstraintNullList : function () { - collection.ensureGeoConstraint("loc", true); - - var d1 = collection.save({ loc : [ 0, 0 ] }); - - collection.save({ a : 1 }); - collection.save({ loc : null }); - - try { - collection.save({ loc : [0] }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.save({ loc : [ -100, -200 ] }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - assertEqual(1, collection.near(0,0).toArray().length); - - collection.replace(d1._id, { a : 1 }); - collection.replace(d1._id, { loc : null }); - - try { - collection.replace(d1._id, { loc : [0] }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.replace(d1._id, { loc : [ -100, -200 ] }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.replace(d1._id, { loc : [ -100, null ] }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.replace(d1._id, { loc : 1 }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - assertEqual(0, collection.near(0,0).toArray().length); - }, - -//////////////////////////////////////////////////////////////////////////////// -/// @brief test: error handling index -//////////////////////////////////////////////////////////////////////////////// - - testErrorHandlingConstraintAttribute : function () { - collection.ensureGeoConstraint("lat", "lon", false); - - var d1 = collection.save({ lat : 0, lon : 0 }); - - try { - collection.save({ a : 1 }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.save({ lat : null, lon : 1 }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.save({ lat : 0 }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.save({ lat : -100, lon : -200 }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - assertEqual(1, collection.near(0,0).toArray().length); - - try { - collection.replace(d1._id, { a : 1 }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.replace(d1._id, { lat : null, lon : 1 }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.replace(d1._id, { lat : 0 }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.replace(d1._id, { lat : -100, lon : -200 }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - assertEqual(1, collection.near(0,0).toArray().length); - }, - -//////////////////////////////////////////////////////////////////////////////// -/// @brief test: error handling index -//////////////////////////////////////////////////////////////////////////////// - - testErrorHandlingConstraintNullList2 : function () { - collection.ensureGeoConstraint("lat", "lon", true); - - var d1 = collection.save({ lat : 0, lon : 0 }); - - collection.save({ a : 1 }); - collection.save({ lat : null, lon : 1 }); - collection.save({ lat : 1, lon : null }); - - try { - collection.save({ lat : "Hello", lon : 10 }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.save({ lat : -100, lon : -200 }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - assertEqual(1, collection.near(0,0).toArray().length); - - collection.replace(d1._id, { a : 1 }); - collection.replace(d1._id, { lat : null }); - - try { - collection.replace(d1._id, { lat : "Hello" }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.replace(d1._id, { lat : -100, lon : -200 }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.replace(d1._id, { lat : -100, lon : "Hello" }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - try { - collection.replace(d1._id, { lat : "Hello", lon : 10 }); - fail(); - } - catch (err) { - assertEqual(ERRORS.ERROR_ARANGO_GEO_INDEX_VIOLATED.code, err.errorNum); - } - - assertEqual(0, collection.near(0,0).toArray().length); } + }; } diff --git a/js/common/tests/shell-index.js b/js/common/tests/shell-index.js index fdd9360e5e..e0be195454 100644 --- a/js/common/tests/shell-index.js +++ b/js/common/tests/shell-index.js @@ -643,8 +643,9 @@ function getIndexesEdgesSuite() { var idx = res[2]; assertEqual("geo2", idx.type); - assertTrue(idx.unique); - assertFalse(idx.ignoreNull); + assertFalse(idx.unique); + assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertEqual([ "lat", "lon" ], idx.fields); assertTrue(idx.hasOwnProperty("id")); assertEqual(collection.name(), idx.id.substr(0, collection.name().length)); @@ -663,8 +664,9 @@ function getIndexesEdgesSuite() { var idx = res[2]; assertEqual("geo2", idx.type); - assertTrue(idx.unique); + assertFalse(idx.unique); assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertEqual([ "lat", "lon" ], idx.fields); assertTrue(idx.hasOwnProperty("id")); assertEqual(collection.name(), idx.id.substr(0, collection.name().length)); @@ -683,9 +685,10 @@ function getIndexesEdgesSuite() { var idx = res[2]; assertEqual("geo1", idx.type); - assertTrue(idx.unique); + assertFalse(idx.unique); assertTrue(idx.geoJson); assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertEqual([ "lat" ], idx.fields); assertTrue(idx.hasOwnProperty("id")); assertEqual(collection.name(), idx.id.substr(0, collection.name().length)); @@ -706,7 +709,8 @@ function getIndexesEdgesSuite() { assertEqual("geo1", idx.type); assertFalse(idx.unique); assertTrue(idx.geoJson); - assertFalse(idx.ignoreNull); + assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertEqual([ "lat" ], idx.fields); assertTrue(idx.hasOwnProperty("id")); assertEqual(collection.name(), idx.id.substr(0, collection.name().length)); @@ -726,7 +730,8 @@ function getIndexesEdgesSuite() { assertEqual("geo2", idx.type); assertFalse(idx.unique); - assertFalse(idx.ignoreNull); + assertTrue(idx.ignoreNull); + assertTrue(idx.sparse); assertEqual([ "lat", "lon" ], idx.fields); assertTrue(idx.hasOwnProperty("id")); assertEqual(collection.name(), idx.id.substr(0, collection.name().length)); diff --git a/js/server/modules/org/arangodb/arango-collection.js b/js/server/modules/org/arangodb/arango-collection.js index aad1583b47..0286bcbc1a 100644 --- a/js/server/modules/org/arangodb/arango-collection.js +++ b/js/server/modules/org/arangodb/arango-collection.js @@ -1201,6 +1201,10 @@ ArangoCollection.prototype.ensureHashIndex = function () { /// All documents which do not have the attribute paths or which values /// are not suitable, are ignored. /// +/// Geo indexes are always sparse, meaning that documents with do not contain +/// the index attributes or have non-numeric values in the index attributes +/// will not be indexed. +/// /// In case that the index was successfully created, an object with the index /// details, including the index-identifier, is returned. /// @@ -1248,57 +1252,23 @@ ArangoCollection.prototype.ensureGeoIndex = function (lat, lon) { //////////////////////////////////////////////////////////////////////////////// /// @brief ensures that a geo constraint exists /// @startDocuBlock collectionEnsureGeoConstraint -/// `collection.ensureGeoConstraint(location, ignore-null)` +/// `collection.ensureGeoConstraint(location)` /// -/// `collection.ensureGeoConstraint(location, true, ignore-null)` +/// `collection.ensureGeoConstraint(location, true)` /// -/// `collection.ensureGeoConstraint(latitude, longitude, ignore-null)` +/// `collection.ensureGeoConstraint(latitude, longitude)` /// -/// Works like *ensureGeoIndex* but requires that the documents contain -/// a valid geo definition. If *ignore-null* is true, then documents with -/// a null in *location* or at least one null in *latitude* or -/// *longitude* are ignored. +/// Since ArangoDB 2.5, this method is an alias for *ensureGeoIndex* since +/// geo indexes are always sparse, meaning that documents that do not contain +/// the index attributes or have non-numeric values in the index attributes +/// will not be indexed. /// @endDocuBlock //////////////////////////////////////////////////////////////////////////////// -ArangoCollection.prototype.ensureGeoConstraint = function (lat, lon, ignoreNull) { +ArangoCollection.prototype.ensureGeoConstraint = function (lat, lon) { "use strict"; - // only two parameter - if (ignoreNull === undefined) { - ignoreNull = lon; - - if (typeof ignoreNull !== "boolean") { - throw "usage: ensureGeoConstraint(, , )" - + " or ensureGeoConstraint(, , )"; - } - - return this.ensureIndex({ - type : "geo1", - fields : [ lat ], - geoJson : false, - unique : true, - ignoreNull : ignoreNull - }); - } - - // three parameter - if (typeof lon === "boolean") { - return this.ensureIndex({ - type : "geo1", - fields : [ lat ], - geoJson : lon, - unique : true, - ignoreNull : ignoreNull - }); - } - - return this.ensureIndex({ - type : "geo2", - fields : [ lat, lon ], - unique : true, - ignoreNull : ignoreNull - }); + return this.ensureGeoIndex(lat, lon); }; ////////////////////////////////////////////////////////////////////////////////