Skip to content

Commit

Permalink
[DE-80] zkd indexes (#417)
Browse files Browse the repository at this point in the history
* zkd indexes

* fixed zkd indexes tests

* fixed merge issue
  • Loading branch information
rashtao authored Jan 12, 2022
1 parent 8c7b665 commit 0f99d4e
Show file tree
Hide file tree
Showing 13 changed files with 259 additions and 22 deletions.
13 changes: 13 additions & 0 deletions src/main/java/com/arangodb/ArangoCollection.java
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,19 @@ <T> MultiDocumentEntity<DocumentDeleteEntity<T>> deleteDocuments(
*/
IndexEntity ensureTtlIndex(Iterable<String> fields, TtlIndexOptions options) throws ArangoDBException;

/**
* Creates a ZKD multi-dimensional index for the collection, if it does not already exist.
* Note that zkd indexes are an experimental feature in ArangoDB 3.9.
*
* @param fields A list of attribute paths
* @param options Additional options, can be null
* @return information about the index
* @throws ArangoDBException
* @see <a href="https://www.arangodb.com/docs/stable/http/indexes-multi-dim.html">API Documentation</a>
* @since ArangoDB 3.9
*/
IndexEntity ensureZKDIndex(Iterable<String> fields, ZKDIndexOptions options) throws ArangoDBException;

/**
* Fetches a list of all indexes on this collection.
*
Expand Down
20 changes: 16 additions & 4 deletions src/main/java/com/arangodb/async/ArangoCollectionAsync.java
Original file line number Diff line number Diff line change
Expand Up @@ -270,10 +270,10 @@ <T> CompletableFuture<DocumentUpdateEntity<T>> updateDocument(
* to patch (the patch document). All attributes from the patch document will be added to the existing document if
* they do not yet exist, and overwritten in the existing document if they do exist there.
*
* @param key The key of the document
* @param value A representation of a single document (POJO, VPackSlice or String for Json)
* @param options Additional options, can be null
* @param returnType Type of the returned newDocument and/or oldDocument
* @param key The key of the document
* @param value A representation of a single document (POJO, VPackSlice or String for Json)
* @param options Additional options, can be null
* @param returnType Type of the returned newDocument and/or oldDocument
* @return information about the document
* @see <a href="https://www.arangodb.com/docs/stable/http/document-working-with-documents.html#update-document">API
* Documentation</a>
Expand Down Expand Up @@ -497,6 +497,18 @@ CompletableFuture<IndexEntity> ensureFulltextIndex(
*/
CompletableFuture<IndexEntity> ensureTtlIndex(Iterable<String> fields, TtlIndexOptions options);

/**
* Creates a ZKD multi-dimensional index for the collection, if it does not already exist.
* Note that zkd indexes are an experimental feature in ArangoDB 3.9.
*
* @param fields A list of attribute paths
* @param options Additional options, can be null
* @return information about the index
* @see <a href="https://www.arangodb.com/docs/stable/http/indexes-multi-dim.html">API Documentation</a>
* @since ArangoDB 3.9
*/
CompletableFuture<IndexEntity> ensureZKDIndex(final Iterable<String> fields, final ZKDIndexOptions options);

/**
* Returns all indexes of the collection
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,13 @@ public CompletableFuture<IndexEntity> ensureTtlIndex(Iterable<String> fields, Tt
return executor.execute(createTtlIndexRequest(fields, options), IndexEntity.class);
}

@Override
public CompletableFuture<IndexEntity> ensureZKDIndex(
final Iterable<String> fields,
final ZKDIndexOptions options) {
return executor.execute(createZKDIndexRequest(fields, options), IndexEntity.class);
}

@Override
public CompletableFuture<Collection<IndexEntity>> getIndexes() {
return executor.execute(getIndexesRequest(), getIndexesResponseDeserializer());
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/arangodb/entity/IndexType.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@
* @author Heiko Kernbach
*/
public enum IndexType {
primary, hash, skiplist, persistent, geo, geo1, geo2, fulltext, edge, ttl
primary, hash, skiplist, persistent, geo, geo1, geo2, fulltext, edge, ttl, zkd
}
6 changes: 6 additions & 0 deletions src/main/java/com/arangodb/internal/ArangoCollectionImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,12 @@ public IndexEntity ensureTtlIndex(final Iterable<String> fields, final TtlIndexO
return executor.execute(createTtlIndexRequest(fields, options), IndexEntity.class);
}

@Override
public IndexEntity ensureZKDIndex(final Iterable<String> fields, final ZKDIndexOptions options)
throws ArangoDBException {
return executor.execute(createZKDIndexRequest(fields, options), IndexEntity.class);
}

@Override
public Collection<IndexEntity> getIndexes() throws ArangoDBException {
return executor.execute(getIndexesRequest(), getIndexesResponseDeserializer());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,15 @@ protected Request createTtlIndexRequest(final Iterable<String> fields, final Ttl
return request;
}

protected Request createZKDIndexRequest(
final Iterable<String> fields, final ZKDIndexOptions options) {
final Request request = request(db.dbName(), RequestType.POST, PATH_API_INDEX);
request.putQueryParam(COLLECTION, name);
request.setBody(util().serialize(OptionsBuilder.build(options != null ? options :
new ZKDIndexOptions().fieldValueTypes(ZKDIndexOptions.FieldValueTypes.DOUBLE), fields)));
return request;
}

protected Request getIndexesRequest() {
final Request request = request(db.dbName(), RequestType.GET, PATH_API_INDEX);
request.putQueryParam(COLLECTION, name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import com.arangodb.entity.arangosearch.analyzer.StopwordsAnalyzer;
import com.arangodb.entity.arangosearch.analyzer.TextAnalyzer;
import com.arangodb.model.CollectionSchema;
import com.arangodb.model.ZKDIndexOptions;
import com.arangodb.velocypack.VPackDeserializer;
import com.arangodb.velocypack.VPackParser;
import com.arangodb.velocypack.VPackSlice;
Expand Down Expand Up @@ -332,4 +333,8 @@ protected static FieldLink deserializeField(final Entry<String, VPackSlice> fiel
return collectionValidation;
};

public static final VPackDeserializer<ZKDIndexOptions.FieldValueTypes> ZKD_FIELD_VALUE_TYPES =
(parent, vpack, context) -> ZKDIndexOptions.FieldValueTypes.valueOf(vpack.getAsString().toUpperCase(Locale.ENGLISH));


}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.arangodb.internal.velocystream.internal.JwtAuthenticationRequest;
import com.arangodb.model.CollectionSchema;
import com.arangodb.model.TraversalOptions;
import com.arangodb.model.ZKDIndexOptions;
import com.arangodb.model.arangosearch.ArangoSearchPropertiesOptions;
import com.arangodb.velocypack.VPackModule;
import com.arangodb.velocypack.VPackParserModule;
Expand Down Expand Up @@ -70,6 +71,7 @@ public <C extends VPackSetupContext<C>> void setup(final C context) {
context.registerSerializer(ArangoSearchProperties.class, VPackSerializers.ARANGO_SEARCH_PROPERTIES);
context.registerSerializer(ConsolidationType.class, VPackSerializers.CONSOLIDATE_TYPE);
context.registerSerializer(CollectionSchema.class, VPackSerializers.COLLECTION_VALIDATION);
context.registerSerializer(ZKDIndexOptions.FieldValueTypes.class, VPackSerializers.ZKD_FIELD_VALUE_TYPES);

context.registerDeserializer(Response.class, VPackDeserializers.RESPONSE);
context.registerDeserializer(CollectionType.class, VPackDeserializers.COLLECTION_TYPE);
Expand All @@ -89,6 +91,7 @@ public <C extends VPackSetupContext<C>> void setup(final C context) {
context.registerDeserializer(ArangoSearchPropertiesEntity.class, VPackDeserializers.ARANGO_SEARCH_PROPERTIES_ENTITY);
context.registerDeserializer(ConsolidationPolicy.class, VPackDeserializers.CONSOLIDATE);
context.registerDeserializer(CollectionSchema.class, VPackDeserializers.COLLECTION_VALIDATION);
context.registerDeserializer(ZKDIndexOptions.FieldValueTypes.class, VPackDeserializers.ZKD_FIELD_VALUE_TYPES);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import com.arangodb.model.CollectionSchema;
import com.arangodb.model.TraversalOptions;
import com.arangodb.model.TraversalOptions.Order;
import com.arangodb.model.ZKDIndexOptions;
import com.arangodb.model.arangosearch.ArangoSearchPropertiesOptions;
import com.arangodb.velocypack.VPackBuilder;
import com.arangodb.velocypack.VPackParser;
Expand Down Expand Up @@ -285,4 +286,7 @@ private static void serializeFieldLinks(final VPackBuilder builder, final Collec
context.serialize(builder, attribute, doc);
};

public static final VPackSerializer<ZKDIndexOptions.FieldValueTypes> ZKD_FIELD_VALUE_TYPES =
(builder, attribute, value, context) -> builder.add(attribute, value.name().toLowerCase(Locale.ENGLISH));

}
4 changes: 4 additions & 0 deletions src/main/java/com/arangodb/model/OptionsBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ public static TtlIndexOptions build(final TtlIndexOptions options, final Iterabl
return options.fields(fields);
}

public static ZKDIndexOptions build(final ZKDIndexOptions options, final Iterable<String> fields) {
return options.fields(fields);
}

public static CollectionCreateOptions build(final CollectionCreateOptions options, final String name) {
return options.name(name);
}
Expand Down
93 changes: 93 additions & 0 deletions src/main/java/com/arangodb/model/ZKDIndexOptions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* DISCLAIMER
*
* Copyright 2016 ArangoDB GmbH, Cologne, Germany
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright holder is ArangoDB GmbH, Cologne, Germany
*/

package com.arangodb.model;

import com.arangodb.entity.IndexType;

/**
* @author Michele Rastelli
* @see <a href="https://www.arangodb.com/docs/stable/http/indexes-multi-dim.html">API Documentation</a>
* @since ArangoDB 3.9
*/
public class ZKDIndexOptions extends IndexOptions<ZKDIndexOptions> {

private Iterable<String> fields;
protected final IndexType type = IndexType.zkd;
private Boolean unique;
private FieldValueTypes fieldValueTypes;

public ZKDIndexOptions() {
super();
}

@Override
protected ZKDIndexOptions getThis() {
return this;
}

protected Iterable<String> getFields() {
return fields;
}

/**
* @param fields A list of attribute paths
* @return options
*/
protected ZKDIndexOptions fields(final Iterable<String> fields) {
this.fields = fields;
return this;
}

protected IndexType getType() {
return type;
}

public Boolean getUnique() {
return unique;
}

/**
* @param unique if true, then create a unique index
* @return options
*/
public ZKDIndexOptions unique(final Boolean unique) {
this.unique = unique;
return this;
}

public FieldValueTypes getFieldValueTypes() {
return fieldValueTypes;
}

/**
* @param fieldValueTypes must be {@link FieldValueTypes#DOUBLE}, currently only doubles are supported as values.
* @return options
*/
public ZKDIndexOptions fieldValueTypes(final FieldValueTypes fieldValueTypes) {
this.fieldValueTypes = fieldValueTypes;
return this;
}

public enum FieldValueTypes {
DOUBLE
}

}
67 changes: 50 additions & 17 deletions src/test/java/com/arangodb/ArangoCollectionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,8 @@
import com.arangodb.entity.MultiDocumentEntity;
import com.arangodb.entity.Permissions;
import com.arangodb.entity.ShardEntity;
import com.arangodb.model.CollectionCreateOptions;
import com.arangodb.model.CollectionPropertiesOptions;
import com.arangodb.model.CollectionSchema;
import com.arangodb.model.DocumentCreateOptions;
import com.arangodb.model.DocumentDeleteOptions;
import com.arangodb.model.DocumentExistsOptions;
import com.arangodb.model.DocumentImportOptions;
import com.arangodb.model.*;
import com.arangodb.model.DocumentImportOptions.OnDuplicate;
import com.arangodb.model.DocumentReadOptions;
import com.arangodb.model.DocumentReplaceOptions;
import com.arangodb.model.DocumentUpdateOptions;
import com.arangodb.model.FulltextIndexOptions;
import com.arangodb.model.GeoIndexOptions;
import com.arangodb.model.HashIndexOptions;
import com.arangodb.model.OverwriteMode;
import com.arangodb.model.PersistentIndexOptions;
import com.arangodb.model.SkiplistIndexOptions;
import com.arangodb.model.TtlIndexOptions;
import com.arangodb.util.MapBuilder;
import com.arangodb.velocypack.VPackSlice;
import com.fasterxml.jackson.core.JsonProcessingException;
Expand Down Expand Up @@ -1429,6 +1413,55 @@ public void createPersistentIndexWithOptions() {
assertThat(indexResult.getName(), is(name));
}

@Test
public void createZKDIndex() {
assumeTrue(isAtLeastVersion(3, 9));
collection.truncate();
String f1 = "field-" + rnd();
String f2 = "field-" + rnd();
final Collection<String> fields = Arrays.asList(f1, f2);

final IndexEntity indexResult = collection.ensureZKDIndex(fields, null);
assertThat(indexResult, is(notNullValue()));
assertThat(indexResult.getConstraint(), is(nullValue()));
assertThat(indexResult.getFields(), hasItem(f1));
assertThat(indexResult.getFields(), hasItem(f2));
assertThat(indexResult.getId(), startsWith(COLLECTION_NAME));
assertThat(indexResult.getIsNewlyCreated(), is(true));
assertThat(indexResult.getMinLength(), is(nullValue()));
assertThat(indexResult.getType(), is(IndexType.zkd));
assertThat(indexResult.getUnique(), is(false));
collection.deleteIndex(indexResult.getId());
}

@Test
public void createZKDIndexWithOptions() {
assumeTrue(isAtLeastVersion(3, 9));
collection.truncate();

String name = "ZKDIndex-" + rnd();
final ZKDIndexOptions options = new ZKDIndexOptions()
.name(name)
.fieldValueTypes(ZKDIndexOptions.FieldValueTypes.DOUBLE);

String f1 = "field-" + rnd();
String f2 = "field-" + rnd();

final Collection<String> fields = Arrays.asList(f1, f2);
final IndexEntity indexResult = collection.ensureZKDIndex(fields, options);
assertThat(indexResult, is(notNullValue()));
assertThat(indexResult.getConstraint(), is(nullValue()));
assertThat(indexResult.getFields(), hasItem(f1));
assertThat(indexResult.getFields(), hasItem(f2));
assertThat(indexResult.getId(), startsWith(COLLECTION_NAME));
assertThat(indexResult.getIsNewlyCreated(), is(true));
assertThat(indexResult.getMinLength(), is(nullValue()));
assertThat(indexResult.getType(), is(IndexType.zkd));
assertThat(indexResult.getUnique(), is(false));
assertThat(indexResult.getName(), is(name));
collection.deleteIndex(indexResult.getId());
}

@Test
public void indexEstimates() {
assumeTrue(isAtLeastVersion(3, 8));
Expand Down
Loading

0 comments on commit 0f99d4e

Please sign in to comment.