Merge pull request #2289 from sl-at-ibm/SL-data-api-adapter-improvements

Major Data API adapter overhaul (milestone 1)
This commit is contained in:
J S authored and GitHub committed 2026-09-28 15:38:08 -05:00
commit 37cd34f0fd
79 files changed
+3390 -841

No files matched your search

+1 -1
View File
@@ -49,7 +49,7 @@
<dependency>
<groupId>com.datastax.astra</groupId>
<artifactId>astra-db-java</artifactId>
<version>2.1.4</version>
<version>2.3.2</version>
</dependency>
<!-- Override Lombok version for Java 25 compatibility -->
<dependency>
@@ -26,10 +26,46 @@ import io.nosqlbench.engine.api.templating.TypeAndTarget;
import io.nosqlbench.nb.api.components.core.NBComponent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.HashMap;
import java.util.Map;
import java.util.function.LongFunction;
public class DataApiOpMapper implements OpMapper<DataApiBaseOp,DataApiSpace> {
private static final Logger logger = LogManager.getLogger(DataApiOpMapper.class);
// Maps a deprecated op type to its replacement, or null if there is no replacement.
private static final Map<DataApiOpType, DataApiOpType> DEPRECATED_OP_TYPES;
static {
DEPRECATED_OP_TYPES = new HashMap<>();
// admin ops:
DEPRECATED_OP_TYPES.put(DataApiOpType.create_collection_with_class, DataApiOpType.db_create_collection);
DEPRECATED_OP_TYPES.put(DataApiOpType.create_collection, DataApiOpType.db_create_collection);
DEPRECATED_OP_TYPES.put(DataApiOpType.delete_collection, DataApiOpType.db_delete_collection);
// db-admin ops:
// in-database ops:
// in-collection ops:
DEPRECATED_OP_TYPES.put(DataApiOpType.insert_one, DataApiOpType.collection_insert_one);
DEPRECATED_OP_TYPES.put(DataApiOpType.insert_one_vector, DataApiOpType.collection_insert_one);
DEPRECATED_OP_TYPES.put(DataApiOpType.insert_many, DataApiOpType.collection_insert_many);
DEPRECATED_OP_TYPES.put(DataApiOpType.delete_all, DataApiOpType.collection_delete_many);
DEPRECATED_OP_TYPES.put(DataApiOpType.delete_many, DataApiOpType.collection_delete_many);
DEPRECATED_OP_TYPES.put(DataApiOpType.delete_one, DataApiOpType.collection_delete_one);
DEPRECATED_OP_TYPES.put(DataApiOpType.find_one_and_delete, DataApiOpType.collection_find_one_and_delete);
DEPRECATED_OP_TYPES.put(DataApiOpType.find, DataApiOpType.collection_find);
DEPRECATED_OP_TYPES.put(DataApiOpType.find_vector, DataApiOpType.collection_find);
DEPRECATED_OP_TYPES.put(DataApiOpType.find_vector_filter, DataApiOpType.collection_find);
DEPRECATED_OP_TYPES.put(DataApiOpType.find_by_id, DataApiOpType.collection_find_one);
DEPRECATED_OP_TYPES.put(DataApiOpType.find_distinct, null); // not a Data API primitive, it's client-emulated
DEPRECATED_OP_TYPES.put(DataApiOpType.find_one, DataApiOpType.collection_find_one);
DEPRECATED_OP_TYPES.put(DataApiOpType.update_one, DataApiOpType.collection_update_one);
DEPRECATED_OP_TYPES.put(DataApiOpType.find_one_and_update, DataApiOpType.collection_find_one_and_update);
DEPRECATED_OP_TYPES.put(DataApiOpType.replace_one, null); // not a Data API primitive, it's client-emulated
DEPRECATED_OP_TYPES.put(DataApiOpType.find_one_and_replace, DataApiOpType.collection_find_one_and_replace);
DEPRECATED_OP_TYPES.put(DataApiOpType.update_many, DataApiOpType.collection_update_many);
DEPRECATED_OP_TYPES.put(DataApiOpType.count_documents, DataApiOpType.collection_count_documents);
DEPRECATED_OP_TYPES.put(DataApiOpType.estimated_document_count, DataApiOpType.collection_estimated_document_count);
}
private final DataApiDriverAdapter adapter;
public DataApiOpMapper(DataApiDriverAdapter dataApiDriverAdapter) {
@@ -47,7 +83,18 @@ public class DataApiOpMapper implements OpMapper<DataApiBaseOp,DataApiSpace> {
"collection"
);
logger.debug(() -> "Using '" + typeAndTarget.enumId + "' op type for op template '" + op.getName() + "'");
if (DEPRECATED_OP_TYPES.containsKey(typeAndTarget.enumId)) {
DataApiOpType replacement = DEPRECATED_OP_TYPES.get(typeAndTarget.enumId);
if (replacement != null) {
logger.warn(() -> "Op type '" + typeAndTarget.enumId + "' is deprecated; please switch to '" +
replacement + "'. Op template: '" + op.getName() + "'");
} else {
logger.warn(() -> "Op type '" + typeAndTarget.enumId + "' is discontinued and will be removed" +
" in a future release. Op template: '" + op.getName() + "'");
}
}
return switch (typeAndTarget.enumId) {
// TO-DO OPS
// admin ops:
case create_database -> new DataApiCreateDatabaseOpDispenser(adapter, op, typeAndTarget.targetFunction);
case list_databases -> new DataApiListDatabasesOpDispenser(adapter, op, typeAndTarget.targetFunction);
@@ -58,34 +105,60 @@ public class DataApiOpMapper implements OpMapper<DataApiBaseOp,DataApiSpace> {
case list_namespaces -> new DataApiListNamespacesOpDispenser(adapter, op, typeAndTarget.targetFunction);
case drop_namespace -> new DataApiDropNamespaceOpDispenser(adapter, op, typeAndTarget.targetFunction);
// in-database ops:
case create_collection -> new DataApiCreateCollectionOpDispenser(adapter, op, typeAndTarget.targetFunction);
case delete_collection -> new DataApiDropCollectionOpDispenser(adapter, op, typeAndTarget.targetFunction);
case list_collections -> new DataApiListCollectionsOpDispenser(adapter, op, typeAndTarget.targetFunction);
case list_collection_names ->
new DataApiListCollectionNamesOpDispenser(adapter, op, typeAndTarget.targetFunction);
case create_collection_with_class -> new DataApiCreateCollectionWithClassOpDispenser(adapter, op, typeAndTarget.targetFunction);
// LEGACY OPS
// admin ops:
// db-admin ops:
// in-database ops:
case create_collection -> new DataApiLegacyCreateCollectionOpDispenser(adapter, op, typeAndTarget.targetFunction);
case create_collection_with_class -> new DataApiLegacyCreateCollectionWithClassOpDispenser(adapter, op, typeAndTarget.targetFunction);
case delete_collection -> new DataApiLegacyDeleteCollectionOpDispenser(adapter, op, typeAndTarget.targetFunction);
// in-collection ops:
case insert_many -> new DataApiCollectionInsertManyOpDispenser(adapter, op, typeAndTarget.targetFunction);
case insert_one -> new DataApiCollectionInsertOneOpDispenser(adapter, op, typeAndTarget.targetFunction);
case insert_one_vector -> new DataApiCollectionInsertOneVectorOpDispenser(adapter, op, typeAndTarget.targetFunction);
case find -> new DataApiCollectionFindOpDispenser(adapter, op, typeAndTarget.targetFunction);
case find_one -> new DataApiCollectionFindOneOpDispenser(adapter, op, typeAndTarget.targetFunction);
case find_one_and_delete -> new DataApiCollectionFindOneAndDeleteOpDispenser(adapter, op, typeAndTarget.targetFunction);
case find_one_and_update -> new DataApiCollectionFindOneAndUpdateOpDispenser(adapter, op, typeAndTarget.targetFunction);
case find_vector -> new DataApiCollectionFindVectorOpDispenser(adapter, op, typeAndTarget.targetFunction);
case find_vector_filter -> new DataApiCollectionFindVectorFilterOpDispenser(adapter, op, typeAndTarget.targetFunction);
case update_one -> new DataApiCollectionUpdateOneOpDispenser(adapter, op, typeAndTarget.targetFunction);
case update_many -> new DataApiCollectionUpdateManyOpDispenser(adapter, op, typeAndTarget.targetFunction);
case delete_one -> new DataApiCollectionDeleteOneOpDispenser(adapter, op, typeAndTarget.targetFunction);
case delete_many -> new DataApiCollectionDeleteManyOpDispenser(adapter, op, typeAndTarget.targetFunction);
case insert_one_vector -> new DataApiCollectionLegacyInsertOneVectorOpDispenser(adapter, op, typeAndTarget.targetFunction);
case insert_many -> new DataApiCollectionLegacyInsertManyOpDispenser(adapter, op, typeAndTarget.targetFunction);
case delete_one -> new DataApiCollectionLegacyDeleteOneOpDispenser(adapter, op, typeAndTarget.targetFunction);
case delete_many -> new DataApiCollectionLegacyDeleteManyOpDispenser(adapter, op, typeAndTarget.targetFunction);
case delete_all -> new DataApiCollectionLegacyDeleteAllOpDispenser(adapter, op, typeAndTarget.targetFunction);
case find_one_and_delete -> new DataApiCollectionLegacyFindOneAndDeleteOpDispenser(adapter, op, typeAndTarget.targetFunction);
case find -> new DataApiCollectionLegacyFindOpDispenser(adapter, op, typeAndTarget.targetFunction);
case find_vector -> new DataApiCollectionLegacyFindVectorOpDispenser(adapter, op, typeAndTarget.targetFunction);
case find_vector_filter -> new DataApiCollectionLegacyFindVectorFilterOpDispenser(adapter, op, typeAndTarget.targetFunction);
case find_by_id -> new DataApiCollectionLegacyFindByIdOpDispenser(adapter, op, typeAndTarget.targetFunction);
case find_distinct -> new DataApiCollectionLegacyFindDistinctOpDispenser(adapter, op, typeAndTarget.targetFunction);
case find_one -> new DataApiCollectionLegacyFindOneOpDispenser(adapter, op, typeAndTarget.targetFunction);
case update_one -> new DataApiCollectionLegacyUpdateOneOpDispenser(adapter, op, typeAndTarget.targetFunction);
case find_one_and_update -> new DataApiCollectionLegacyFindOneAndUpdateOpDispenser(adapter, op, typeAndTarget.targetFunction);
case replace_one -> new DataApiCollectionLegacyReplaceOneOpDispenser(adapter, op, typeAndTarget.targetFunction);
case find_one_and_replace -> new DataApiCollectionLegacyFindOneAndReplaceOpDispenser(adapter, op, typeAndTarget.targetFunction);
case update_many -> new DataApiCollectionLegacyUpdateManyOpDispenser(adapter, op, typeAndTarget.targetFunction);
case count_documents -> new DataApiCollectionLegacyCountDocumentsOpDispenser(adapter, op, typeAndTarget.targetFunction);
case estimated_document_count ->
new DataApiCollectionEstimatedDocumentCountOpDispenser(adapter, op, typeAndTarget.targetFunction);
case find_by_id -> new DataApiCollectionFindByIdOpDispenser(adapter, op, typeAndTarget.targetFunction);
case find_distinct -> new DataApiCollectionFindDistinctOpDispenser(adapter, op, typeAndTarget.targetFunction);
case count_documents -> new DataApiCollectionCountDocumentsOpDispenser(adapter, op, typeAndTarget.targetFunction);
case replace_one -> new DataApiCollectionReplaceOneOpDispenser(adapter, op, typeAndTarget.targetFunction);
case find_one_and_replace -> new DataApiCollectionFindOneAndReplaceOpDispenser(adapter, op, typeAndTarget.targetFunction);
case delete_all -> new DataApiCollectionDeleteAllOpDispenser(adapter, op, typeAndTarget.targetFunction);
// NEW-STYLE OPS
// in-database ops:
case db_create_collection -> new DataApiDbCreateCollectionOpDispenser(adapter, op, typeAndTarget.targetFunction);
case db_delete_collection -> new DataApiDbDeleteCollectionOpDispenser(adapter, op, typeAndTarget.targetFunction);
// in-collection ops:
case collection_insert_one -> new DataApiCollectionInsertOneOpDispenser(adapter, op, typeAndTarget.targetFunction);
case collection_insert_many -> new DataApiCollectionInsertManyOpDispenser(adapter, op, typeAndTarget.targetFunction);
case collection_find -> new DataApiCollectionFindOpDispenser(adapter, op, typeAndTarget.targetFunction);
case collection_find_one -> new DataApiCollectionFindOneOpDispenser(adapter, op, typeAndTarget.targetFunction);
case collection_find_and_rerank -> new DataApiCollectionFindAndRerankOpDispenser(adapter, op, typeAndTarget.targetFunction);
case collection_update_one -> new DataApiCollectionUpdateOneOpDispenser(adapter, op, typeAndTarget.targetFunction);
case collection_find_one_and_update -> new DataApiCollectionFindOneAndUpdateOpDispenser(adapter, op, typeAndTarget.targetFunction);
case collection_delete_many -> new DataApiCollectionDeleteManyOpDispenser(adapter, op, typeAndTarget.targetFunction);
case collection_delete_one -> new DataApiCollectionDeleteOneOpDispenser(adapter, op, typeAndTarget.targetFunction);
case collection_find_one_and_delete -> new DataApiCollectionFindOneAndDeleteOpDispenser(adapter, op, typeAndTarget.targetFunction);
case collection_find_one_and_replace -> new DataApiCollectionFindOneAndReplaceOpDispenser(adapter, op, typeAndTarget.targetFunction);
case collection_update_many -> new DataApiCollectionUpdateManyOpDispenser(adapter, op, typeAndTarget.targetFunction);
case collection_estimated_document_count ->
new DataApiCollectionEstimatedDocumentCountOpDispenser(adapter, op, typeAndTarget.targetFunction);
case collection_count_documents -> new DataApiCollectionCountDocumentsOpDispenser(adapter, op, typeAndTarget.targetFunction);
};
}
@@ -20,6 +20,9 @@ import com.datastax.astra.client.DataAPIClient;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.admin.AstraDBAdmin;
import com.datastax.astra.client.admin.DatabaseAdmin;
// TODO: remove this - it's to log Data API requests and responses
import com.datastax.astra.client.core.options.DataAPIClientOptions;
import io.nosqlbench.adapters.api.activityimpl.uniform.BaseSpace;
import io.nosqlbench.nb.api.config.standard.ConfigModel;
import io.nosqlbench.nb.api.config.standard.NBConfigModel;
@@ -26,6 +26,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.function.LongFunction;
import java.util.Optional;
public class DataApiCollectionCountDocumentsOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionCountDocumentsOpDispenser.class);
@@ -40,7 +41,13 @@ public class DataApiCollectionCountDocumentsOpDispenser extends DataApiOpDispens
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
Filter filter = getFilterFromOp(op, l);
int upperBound = op.getAsRequiredFunction("upperbound", Integer.class).apply(l);
Optional<LongFunction<Integer>> ubf = op.getAsOptionalFunction("upper_bound", Integer.class);
Optional<Integer> upperBound;
if (ubf.isPresent()) {
upperBound = Optional.of(ubf.get().apply(l));
} else {
upperBound = Optional.empty();
}
return new DataApiCollectionCountDocumentsOp(
db,
@@ -55,23 +55,13 @@ public class DataApiCollectionDeleteOneOpDispenser extends DataApiOpDispenser {
private CollectionDeleteOneOptions getCollectionDeleteOneOptions(ParsedOp op, long l) {
CollectionDeleteOneOptions options = new CollectionDeleteOneOptions();
Sort sort = getSortFromOp(op, l);
float[] vector = getVectorFromOp(op, l);
if (sort != null) {
options = (vector != null) ? options.sort(Sort.vector(vector), sort) : options.sort(sort);
} else if (vector != null) {
options = options.sort(Sort.vector(vector));
Sort[] sorts = getSortFromOp(op, l);
if (sorts != null) {
options = options.sort(sorts);
}
return options;
}
private float[] getVectorFromOp(ParsedOp op, long l) {
if (op.isDefined("vector")) {
return getVectorValues(op.get("vector", l));
}
return null;
}
@Override
public DataApiBaseOp getOp(long cycle) {
return opFunction.apply(cycle);
@@ -0,0 +1,117 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.opdispensers;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.collections.commands.options.CollectionFindAndRerankOptions;
import com.datastax.astra.client.core.query.Sort;
import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.core.query.Projection;
import com.datastax.astra.client.core.rerank.RerankServiceOptions;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionFindAndRerankOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.function.LongFunction;
import java.util.Map;
import java.util.Optional;
public class DataApiCollectionFindAndRerankOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionFindAndRerankOpDispenser.class);
private final LongFunction<DataApiCollectionFindAndRerankOp> opFunction;
public DataApiCollectionFindAndRerankOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionFindAndRerankOp> createOpFunction(ParsedOp op) {
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
Filter filter = getFilterFromOp(op, l);
CollectionFindAndRerankOptions options = getCollectionFindAndRerankOptions(op, l);
return new DataApiCollectionFindAndRerankOp(
db,
db.getCollection(targetFunction.apply(l)),
filter,
options
);
};
}
private CollectionFindAndRerankOptions getCollectionFindAndRerankOptions(ParsedOp op, long l) {
CollectionFindAndRerankOptions options = new CollectionFindAndRerankOptions();
Sort sort = getFindAndRerankSortFromOp(op, l);
options = options.sort(sort);
Projection[] projection = getProjectionFromOp(op, l);
if (projection != null) {
options = options.projection(projection);
}
Optional<Integer> limit = getLimitFromOp(op, l);
if (limit.isPresent()) {
options = options.limit(limit.get());
}
Optional<Boolean> includeSortVector = getIncludeSortVectorFromOp(op, l);
if (includeSortVector.isPresent()) {
options = options.includeSortVector(includeSortVector.get());
}
Optional<Boolean> includeScores = getIncludeScoresFromOp(op, l);
if (includeScores.isPresent()) {
options = options.includeScores(includeScores.get());
}
Optional<String> rerankQuery = getRerankQueryFromOp(op, l);
if (rerankQuery.isPresent()) {
options = options.rerankQuery(rerankQuery.get());
}
Optional<String> rerankOn = getRerankOnFromOp(op, l);
if (rerankOn.isPresent()) {
options = options.rerankOn(rerankOn.get());
}
Optional<Object> hybridLimits = getHybridLimitsFromOp(op, l);
if (hybridLimits.isPresent()) {
Object hl = hybridLimits.get();
if (hl instanceof Integer i) {
options = options.hybridLimits(i);
} else {
@SuppressWarnings("unchecked")
Map<String, Integer> hlMap = (Map<String, Integer>) hl;
options = options.hybridLimits(hlMap);
}
}
Optional<RerankServiceOptions> rerankService = getRerankServiceFromOp(op, l);
if (rerankService.isPresent()) {
options = options.rerankService(rerankService.get());
}
// TEMP
RerankServiceOptions rop = new RerankServiceOptions();
rop.provider("providerZ");
rop.modelName("modelNameZ");
options = options.rerankService(rop);
// END TEMP
return options;
}
@Override
public DataApiBaseOp getOp(long cycle) {
return opFunction.apply(cycle);
}
}
@@ -56,9 +56,9 @@ public class DataApiCollectionFindOneAndDeleteOpDispenser extends DataApiOpDispe
private CollectionFindOneAndDeleteOptions getCollectionFindOneAndDeleteOptions(ParsedOp op, long l) {
CollectionFindOneAndDeleteOptions options = new CollectionFindOneAndDeleteOptions();
Sort sort = getSortFromOp(op, l);
if (sort != null) {
options = options.sort(sort);
Sort[] sorts = getSortFromOp(op, l);
if (sorts != null) {
options = options.sort(sorts);
}
Projection[] projection = getProjectionFromOp(op, l);
if (projection != null) {
@@ -30,8 +30,6 @@ import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Map;
import java.util.Optional;
import java.util.function.LongFunction;
public class DataApiCollectionFindOneAndReplaceOpDispenser extends DataApiOpDispenser {
@@ -48,14 +46,13 @@ public class DataApiCollectionFindOneAndReplaceOpDispenser extends DataApiOpDisp
Database db = spaceFunction.apply(l).getDatabase();
Filter filter = getFilterFromOp(op, l);
CollectionFindOneAndReplaceOptions options = getCollectionFindOneAndReplaceOptions(op, l);
LongFunction<Map> docMapFunc = op.getAsRequiredFunction("document", Map.class);
LongFunction<Document> docFunc = (long m) -> new Document(docMapFunc.apply(m));
Document replacement = getReplacementFromOp(op, l);
return new DataApiCollectionFindOneAndReplaceOp(
db,
db.getCollection(targetFunction.apply(l)),
filter,
docFunc.apply(l),
replacement,
options
);
};
@@ -63,29 +60,21 @@ public class DataApiCollectionFindOneAndReplaceOpDispenser extends DataApiOpDisp
private CollectionFindOneAndReplaceOptions getCollectionFindOneAndReplaceOptions(ParsedOp op, long l) {
CollectionFindOneAndReplaceOptions options = new CollectionFindOneAndReplaceOptions();
Sort sort = getSortFromOp(op, l);
if (op.isDefined("vector")) {
float[] vector = getVectorValues(op, l);
if (sort != null) {
options = vector != null ? options.sort(Sort.vector(vector), sort) : options.sort(sort);
} else if (vector != null) {
options = options.sort(Sort.vector(vector));
}
Sort[] sorts = getSortFromOp(op, l);
if (sorts != null) {
options = options.sort(sorts);
}
Projection[] projection = getProjectionFromOp(op, l);
if (projection != null) {
options = options.projection(projection);
}
Optional<LongFunction<Boolean>> upsertFunction = op.getAsOptionalFunction("upsert", Boolean.class);
if (upsertFunction.isPresent()) {
options = options.upsert(upsertFunction.get().apply(l));
Boolean upsert = getUpsertFromOp(op, l);
if (upsert != null) {
options = options.upsert(upsert);
}
if (op.isDefined("returnDocument")) {
options = switch ((String) op.get("returnDocument", l)) {
case "after" -> options.returnDocument(ReturnDocument.AFTER);
case "before" -> options.returnDocument(ReturnDocument.BEFORE);
default -> throw new RuntimeException("Invalid returnDocument value: " + op.get("returnDocument", l));
};
ReturnDocument returnDocument = getReturnDocumentFromOp(op, l);
if (returnDocument != null){
options = options.returnDocument(returnDocument);
}
return options;
}
@@ -18,7 +18,11 @@ package io.nosqlbench.adapter.dataapi.opdispensers;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.core.query.Sort;
import com.datastax.astra.client.collections.commands.Update;
import com.datastax.astra.client.collections.commands.options.CollectionDeleteOneOptions;
import com.datastax.astra.client.collections.commands.options.CollectionFindOneAndUpdateOptions;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionFindOneAndUpdateOp;
@@ -40,17 +44,32 @@ public class DataApiCollectionFindOneAndUpdateOpDispenser extends DataApiOpDispe
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
Filter filter = getFilterFromOp(op, l);
Update update = getUpdates(op, l);
Update update = getUpdateFromOp(op, l);
CollectionFindOneAndUpdateOptions options = getCollectionFindOneAndUpdateOptions(op, l);
return new DataApiCollectionFindOneAndUpdateOp(
db,
db.getCollection(targetFunction.apply(l)),
filter,
update
update,
options
);
};
}
private CollectionFindOneAndUpdateOptions getCollectionFindOneAndUpdateOptions(ParsedOp op, long l) {
CollectionFindOneAndUpdateOptions options = new CollectionFindOneAndUpdateOptions();
Sort[] sorts = getSortFromOp(op, l);
Boolean upsert = getUpsertFromOp(op, l);
if (sorts != null) {
options = options.sort(sorts);
}
if ( upsert != null ){
options = options.upsert(upsert);
}
return options;
}
@Override
public DataApiBaseOp getOp(long cycle) {
return opFunction.apply(cycle);
@@ -28,6 +28,7 @@ import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Optional;
import java.util.function.LongFunction;
public class DataApiCollectionFindOneOpDispenser extends DataApiOpDispenser {
@@ -54,18 +55,18 @@ public class DataApiCollectionFindOneOpDispenser extends DataApiOpDispenser {
private CollectionFindOneOptions getCollectionFindOneOptions(ParsedOp op, long l) {
CollectionFindOneOptions options = new CollectionFindOneOptions();
Sort sort = getSortFromOp(op, l);
float[] vector = getVectorValues(op, l);
if (sort != null) {
options = vector != null ? options.sort(Sort.vector(vector), sort) : options.sort(sort);
} else if (vector != null) {
options = options.sort(Sort.vector(vector));
Sort[] sorts = getSortFromOp(op, l);
if (sorts != null) {
options = options.sort(sorts);
}
Projection[] projection = getProjectionFromOp(op, l);
if (projection != null) {
options = options.projection(projection);
}
options.includeSimilarity(true);
Optional<Boolean> includeSimilarity = getIncludeSimilarityFromOp(op, l);
if (includeSimilarity.isPresent()) {
options.includeSimilarity(includeSimilarity.get());
}
return options;
}
@@ -55,34 +55,29 @@ public class DataApiCollectionFindOpDispenser extends DataApiOpDispenser {
private CollectionFindOptions getCollectionFindOptions(ParsedOp op, long l) {
CollectionFindOptions options = new CollectionFindOptions();
Sort sort = getSortFromOp(op, l);
if (op.isDefined("vector")) {
float[] vector = getVectorValues(op, l);
if (sort != null) {
options = vector != null ? options.sort(Sort.vector(vector), sort) : options.sort(sort);
} else if (vector != null) {
options = options.sort(Sort.vector(vector));
}
Sort[] sorts = getSortFromOp(op, l);
if (sorts != null) {
options = options.sort(sorts);
}
Projection[] projection = getProjectionFromOp(op, l);
if (projection != null) {
options = options.projection(projection);
}
Optional<LongFunction<Integer>> limitFunction = op.getAsOptionalFunction("limit", Integer.class);
if (limitFunction.isPresent()) {
options = options.limit(limitFunction.get().apply(l));
Optional<Integer> limit = getLimitFromOp(op, l);
if (limit.isPresent()) {
options = options.limit(limit.get());
}
Optional<LongFunction<Integer>> skipFunction = op.getAsOptionalFunction("skip", Integer.class);
if (skipFunction.isPresent()) {
options = options.skip(skipFunction.get().apply(l));
Optional<Integer> skip = getSkipFromOp(op, l);
if (skip.isPresent()) {
options = options.skip(skip.get());
}
Optional<LongFunction<Boolean>> includeSimilarityFunction = op.getAsOptionalFunction("includeSimilarity", Boolean.class);
if (includeSimilarityFunction.isPresent()) {
options.includeSimilarity(includeSimilarityFunction.get().apply(l));
Optional<Boolean> includeSortVector = getIncludeSortVectorFromOp(op, l);
if (includeSortVector.isPresent()) {
options = options.includeSortVector(includeSortVector.get());
}
Optional<LongFunction<String>> pageStateFunction = op.getAsOptionalFunction("pageState", String.class);
if (pageStateFunction.isPresent()) {
options.pageState(pageStateFunction.get().apply(l));
Optional<Boolean> includeSimilarity = getIncludeSimilarityFromOp(op, l);
if (includeSimilarity.isPresent()) {
options.includeSimilarity(includeSimilarity.get());
}
return options;
}
@@ -42,8 +42,7 @@ public class DataApiCollectionInsertManyOpDispenser extends DataApiOpDispenser {
private LongFunction<DataApiCollectionInsertManyOp> createOpFunction(ParsedOp op) {
return (l) -> {
List<Document> documents = new ArrayList<>();
op.getAsRequiredFunction("documents", List.class).apply(l).forEach(o -> documents.add(Document.parse(o.toString())));
List<Document> documents = getDocumentsFromOp(op, l);
return new DataApiCollectionInsertManyOp(
spaceFunction.apply(l).getDatabase(),
targetFunction.apply(l),
@@ -55,21 +54,15 @@ public class DataApiCollectionInsertManyOpDispenser extends DataApiOpDispenser {
private CollectionInsertManyOptions getCollectionInsertManyOptions(ParsedOp op, long l) {
CollectionInsertManyOptions options = new CollectionInsertManyOptions();
Optional<LongFunction<Map>> optionsFunction = op.getAsOptionalFunction("options", Map.class);
if (optionsFunction.isPresent()) {
Map<String, String> optionFields = optionsFunction.get().apply(l);
for(Map.Entry<String,String> entry: optionFields.entrySet()) {
switch(entry.getKey()) {
case "chunkSize"->
options = options.chunkSize(Integer.parseInt(entry.getValue()));
case "concurrency" ->
options = options.concurrency(Integer.parseInt(entry.getValue()));
case "ordered" ->
options = options.ordered(Boolean.parseBoolean(entry.getValue()));
case "timeout" ->
options = options.timeout(Integer.parseInt(entry.getValue()));
}
}
options = options.concurrency(1); // hardcoded: avoid client concurrency, let NB use its own.
Integer chunkSize = getChunkSizeFromOp(op, l);
if (chunkSize != null) {
logger.warn(() -> "Setting insertion 'chunk_size'. This is discouraged, as it usually signals an intention to not have 1:1 between ops and HTTP requests.");
options = options.chunkSize(chunkSize);
}
Boolean ordered = getOrderedFromOp(op, l);
if (ordered != null) {
options = options.ordered(ordered);
}
return options;
}
@@ -37,13 +37,12 @@ public class DataApiCollectionInsertOneOpDispenser extends DataApiOpDispenser {
}
private LongFunction<DataApiCollectionInsertOneOp> createOpFunction(ParsedOp op) {
LongFunction<Map> docMapFunc = op.getAsRequiredFunction("document", Map.class);
LongFunction<Document> docFunc = (long m) -> new Document(docMapFunc.apply(m));
return (l) -> {
Document document = getDocumentFromOp(op, l);
return new DataApiCollectionInsertOneOp(
spaceFunction.apply(l).getDatabase(),
targetFunction.apply(l),
docFunc.apply(l)
document
);
};
}
@@ -0,0 +1,58 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.opdispensers;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.core.query.Filter;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionLegacyCountDocumentsOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.function.LongFunction;
public class DataApiCollectionLegacyCountDocumentsOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionLegacyCountDocumentsOpDispenser.class);
private final LongFunction<DataApiCollectionLegacyCountDocumentsOp> opFunction;
public DataApiCollectionLegacyCountDocumentsOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionLegacyCountDocumentsOp> createOpFunction(ParsedOp op) {
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
Filter filter = legacyGetFilterFromOp(op, l);
int upperBound = op.getAsRequiredFunction("upperbound", Integer.class).apply(l);
return new DataApiCollectionLegacyCountDocumentsOp(
db,
db.getCollection(targetFunction.apply(l)),
filter,
upperBound
);
};
}
@Override
public DataApiBaseOp getOp(long cycle) {
return opFunction.apply(cycle);
}
}
@@ -19,27 +19,27 @@ package io.nosqlbench.adapter.dataapi.opdispensers;
import com.datastax.astra.client.databases.Database;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionDeleteAllOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionLegacyDeleteAllOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.function.LongFunction;
public class DataApiCollectionDeleteAllOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionDeleteAllOpDispenser.class);
private final LongFunction<DataApiCollectionDeleteAllOp> opFunction;
public class DataApiCollectionLegacyDeleteAllOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionLegacyDeleteAllOpDispenser.class);
private final LongFunction<DataApiCollectionLegacyDeleteAllOp> opFunction;
public DataApiCollectionDeleteAllOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
public DataApiCollectionLegacyDeleteAllOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionDeleteAllOp> createOpFunction(ParsedOp op) {
private LongFunction<DataApiCollectionLegacyDeleteAllOp> createOpFunction(ParsedOp op) {
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
return new DataApiCollectionDeleteAllOp(
return new DataApiCollectionLegacyDeleteAllOp(
db,
db.getCollection(targetFunction.apply(l))
);
@@ -0,0 +1,56 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.opdispensers;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.core.query.Filter;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionDeleteManyOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.function.LongFunction;
public class DataApiCollectionLegacyDeleteManyOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionLegacyDeleteManyOpDispenser.class);
private final LongFunction<DataApiCollectionDeleteManyOp> opFunction;
public DataApiCollectionLegacyDeleteManyOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionDeleteManyOp> createOpFunction(ParsedOp op) {
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
Filter filter = legacyGetFilterFromOp(op, l);
return new DataApiCollectionDeleteManyOp(
db,
db.getCollection(targetFunction.apply(l)),
filter
);
};
}
@Override
public DataApiBaseOp getOp(long cycle) {
return opFunction.apply(cycle);
}
}
@@ -0,0 +1,69 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.opdispensers;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.collections.commands.options.CollectionDeleteOneOptions;
import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.core.query.Sort;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionDeleteOneOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.function.LongFunction;
public class DataApiCollectionLegacyDeleteOneOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionLegacyDeleteOneOpDispenser.class);
private final LongFunction<DataApiCollectionDeleteOneOp> opFunction;
public DataApiCollectionLegacyDeleteOneOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionDeleteOneOp> createOpFunction(ParsedOp op) {
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
Filter filter = legacyGetFilterFromOp(op, l);
CollectionDeleteOneOptions options = getCollectionDeleteOneOptions(op, l);
return new DataApiCollectionDeleteOneOp(
db,
db.getCollection(targetFunction.apply(l)),
filter,
options
);
};
}
private CollectionDeleteOneOptions getCollectionDeleteOneOptions(ParsedOp op, long l) {
CollectionDeleteOneOptions options = new CollectionDeleteOneOptions();
Sort[] sorts = legacyGetSortFromOp(op, l);
if (sorts != null) {
options = options.sort(sorts);
}
return options;
}
@Override
public DataApiBaseOp getOp(long cycle) {
return opFunction.apply(cycle);
}
}
@@ -22,7 +22,7 @@ import com.datastax.astra.client.core.query.Projection;
import com.datastax.astra.client.core.query.Sort;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionFindByIdOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionLegacyFindByIdOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionFindOneOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
@@ -30,19 +30,19 @@ import org.apache.logging.log4j.Logger;
import java.util.function.LongFunction;
public class DataApiCollectionFindByIdOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionFindByIdOpDispenser.class);
private final LongFunction<DataApiCollectionFindByIdOp> opFunction;
public DataApiCollectionFindByIdOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
public class DataApiCollectionLegacyFindByIdOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionLegacyFindByIdOpDispenser.class);
private final LongFunction<DataApiCollectionLegacyFindByIdOp> opFunction;
public DataApiCollectionLegacyFindByIdOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionFindByIdOp> createOpFunction(ParsedOp op) {
private LongFunction<DataApiCollectionLegacyFindByIdOp> createOpFunction(ParsedOp op) {
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
Object id = getIdFromOp(op, l);
return new DataApiCollectionFindByIdOp(
return new DataApiCollectionLegacyFindByIdOp(
db,
db.getCollection(targetFunction.apply(l)),
id
@@ -21,27 +21,27 @@ import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.core.query.Filter;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionFindDistinctOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionLegacyFindDistinctOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.function.LongFunction;
public class DataApiCollectionFindDistinctOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionFindDistinctOpDispenser.class);
private final LongFunction<DataApiCollectionFindDistinctOp> opFunction;
public DataApiCollectionFindDistinctOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
public class DataApiCollectionLegacyFindDistinctOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionLegacyFindDistinctOpDispenser.class);
private final LongFunction<DataApiCollectionLegacyFindDistinctOp> opFunction;
public DataApiCollectionLegacyFindDistinctOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionFindDistinctOp> createOpFunction(ParsedOp op) {
private LongFunction<DataApiCollectionLegacyFindDistinctOp> createOpFunction(ParsedOp op) {
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
Filter filter = getFilterFromOp(op, l);
Filter filter = legacyGetFilterFromOp(op, l);
Class<?> targetClass = getTargetClass(op, l);
return new DataApiCollectionFindDistinctOp(
return new DataApiCollectionLegacyFindDistinctOp(
db,
db.getCollection(targetFunction.apply(l)),
op.getAsRequiredFunction("fieldName", String.class).apply(l),
@@ -0,0 +1,74 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.opdispensers;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.collections.commands.options.CollectionFindOneAndDeleteOptions;
import com.datastax.astra.client.core.query.Projection;
import com.datastax.astra.client.core.query.Sort;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionFindOneAndDeleteOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.function.LongFunction;
public class DataApiCollectionLegacyFindOneAndDeleteOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionLegacyFindOneAndDeleteOpDispenser.class);
private final LongFunction<DataApiCollectionFindOneAndDeleteOp> opFunction;
public DataApiCollectionLegacyFindOneAndDeleteOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionFindOneAndDeleteOp> createOpFunction(ParsedOp op) {
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
Filter filter = legacyGetFilterFromOp(op, l);
CollectionFindOneAndDeleteOptions options = getCollectionFindOneAndDeleteOptions(op, l);
return new DataApiCollectionFindOneAndDeleteOp(
db,
db.getCollection(targetFunction.apply(l)),
filter,
options
);
};
}
private CollectionFindOneAndDeleteOptions getCollectionFindOneAndDeleteOptions(ParsedOp op, long l) {
CollectionFindOneAndDeleteOptions options = new CollectionFindOneAndDeleteOptions();
Sort[] sorts = legacyGetSortFromOp(op, l);
if (sorts != null) {
options = options.sort(sorts);
}
Projection[] projection = getProjectionFromOp(op, l);
if (projection != null) {
options = options.projection(projection);
}
return options;
}
@Override
public DataApiBaseOp getOp(long cycle) {
return opFunction.apply(cycle);
}
}
@@ -0,0 +1,92 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.opdispensers;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.core.query.Filter;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import com.datastax.astra.client.collections.commands.ReturnDocument;
import com.datastax.astra.client.collections.commands.options.CollectionFindOneAndReplaceOptions;
import com.datastax.astra.client.core.query.Projection;
import com.datastax.astra.client.core.query.Sort;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import com.datastax.astra.client.collections.definition.documents.Document;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionFindOneAndReplaceOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Map;
import java.util.Optional;
import java.util.function.LongFunction;
public class DataApiCollectionLegacyFindOneAndReplaceOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionLegacyFindOneAndReplaceOpDispenser.class);
private final LongFunction<DataApiCollectionFindOneAndReplaceOp> opFunction;
public DataApiCollectionLegacyFindOneAndReplaceOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionFindOneAndReplaceOp> createOpFunction(ParsedOp op) {
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
Filter filter = legacyGetFilterFromOp(op, l);
CollectionFindOneAndReplaceOptions options = getCollectionFindOneAndReplaceOptions(op, l);
LongFunction<Map> docMapFunc = op.getAsRequiredFunction("document", Map.class);
LongFunction<Document> docFunc = (long m) -> new Document(docMapFunc.apply(m));
return new DataApiCollectionFindOneAndReplaceOp(
db,
db.getCollection(targetFunction.apply(l)),
filter,
docFunc.apply(l),
options
);
};
}
private CollectionFindOneAndReplaceOptions getCollectionFindOneAndReplaceOptions(ParsedOp op, long l) {
CollectionFindOneAndReplaceOptions options = new CollectionFindOneAndReplaceOptions();
Sort[] sorts = legacyGetSortFromOp(op, l);
if (sorts != null) {
options = options.sort(sorts);
}
Projection[] projection = getProjectionFromOp(op, l);
if (projection != null) {
options = options.projection(projection);
}
Optional<LongFunction<Boolean>> upsertFunction = op.getAsOptionalFunction("upsert", Boolean.class);
if (upsertFunction.isPresent()) {
options = options.upsert(upsertFunction.get().apply(l));
}
if (op.isDefined("returnDocument")) {
options = switch ((String) op.get("returnDocument", l)) {
case "after" -> options.returnDocument(ReturnDocument.AFTER);
case "before" -> options.returnDocument(ReturnDocument.BEFORE);
default -> throw new RuntimeException("Invalid returnDocument value: " + op.get("returnDocument", l));
};
}
return options;
}
@Override
public DataApiBaseOp getOp(long cycle) {
return opFunction.apply(cycle);
}
}
@@ -0,0 +1,76 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.opdispensers;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.core.query.Sort;
import com.datastax.astra.client.collections.commands.Update;
import com.datastax.astra.client.collections.commands.options.CollectionFindOneAndUpdateOptions;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionLegacyFindOneAndUpdateOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.function.LongFunction;
public class DataApiCollectionLegacyFindOneAndUpdateOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionLegacyFindOneAndUpdateOpDispenser.class);
private final LongFunction<DataApiCollectionLegacyFindOneAndUpdateOp> opFunction;
public DataApiCollectionLegacyFindOneAndUpdateOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionLegacyFindOneAndUpdateOp> createOpFunction(ParsedOp op) {
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
Filter filter = legacyGetFilterFromOp(op, l);
Update update = legacyGetUpdateFromOp(op, l);
CollectionFindOneAndUpdateOptions options = getCollectionLegacyFindOneAndUpdateOptions(op, l);
return new DataApiCollectionLegacyFindOneAndUpdateOp(
db,
db.getCollection(targetFunction.apply(l)),
filter,
update,
options
);
};
}
private CollectionFindOneAndUpdateOptions getCollectionLegacyFindOneAndUpdateOptions(ParsedOp op, long l) {
CollectionFindOneAndUpdateOptions options = new CollectionFindOneAndUpdateOptions();
Sort[] sorts = legacyGetSortFromOp(op, l);
Boolean upsert = getUpsertFromOp(op, l);
if (sorts != null) {
options = options.sort(sorts);
}
if ( upsert != null ){
options = options.upsert(upsert);
}
return options;
}
@Override
public DataApiBaseOp getOp(long cycle) {
return opFunction.apply(cycle);
}
}
@@ -0,0 +1,80 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.opdispensers;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.collections.commands.options.CollectionFindOneOptions;
import com.datastax.astra.client.core.query.Projection;
import com.datastax.astra.client.core.query.Sort;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionFindOneOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Optional;
import java.util.function.LongFunction;
public class DataApiCollectionLegacyFindOneOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionLegacyFindOneOpDispenser.class);
private final LongFunction<DataApiCollectionFindOneOp> opFunction;
public DataApiCollectionLegacyFindOneOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionFindOneOp> createOpFunction(ParsedOp op) {
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
Filter filter = legacyGetFilterFromOp(op, l);
CollectionFindOneOptions options = getCollectionFindOneOptions(op, l);
return new DataApiCollectionFindOneOp(
db,
db.getCollection(targetFunction.apply(l)),
filter,
options
);
};
}
private CollectionFindOneOptions getCollectionFindOneOptions(ParsedOp op, long l) {
CollectionFindOneOptions options = new CollectionFindOneOptions();
Sort[] sorts = legacyGetSortFromOp(op, l);
if (sorts != null) {
options = options.sort(sorts);
}
Projection[] projection = getProjectionFromOp(op, l);
if (projection != null) {
options = options.projection(projection);
}
Optional<Boolean> includeSimilarity = getIncludeSimilarityFromOp(op, l);
if (includeSimilarity.isPresent()) {
options.includeSimilarity(includeSimilarity.get());
} else {
// defaulting to true (backward-compatibility)
options.includeSimilarity(true);
}
return options;
}
@Override
public DataApiBaseOp getOp(long cycle) {
return opFunction.apply(cycle);
}
}
@@ -0,0 +1,89 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.opdispensers;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.collections.commands.options.CollectionFindOptions;
import com.datastax.astra.client.core.query.Projection;
import com.datastax.astra.client.core.query.Sort;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionFindOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Optional;
import java.util.function.LongFunction;
public class DataApiCollectionLegacyFindOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionLegacyFindOpDispenser.class);
private final LongFunction<DataApiCollectionFindOp> opFunction;
public DataApiCollectionLegacyFindOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionFindOp> createOpFunction(ParsedOp op) {
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
Filter filter = legacyGetFilterFromOp(op, l);
CollectionFindOptions options = getCollectionFindOptions(op, l);
return new DataApiCollectionFindOp(
db,
db.getCollection(targetFunction.apply(l)),
filter,
options
);
};
}
private CollectionFindOptions getCollectionFindOptions(ParsedOp op, long l) {
CollectionFindOptions options = new CollectionFindOptions();
Sort[] sorts = legacyGetSortFromOp(op, l);
if (sorts != null) {
options = options.sort(sorts);
}
Projection[] projection = getProjectionFromOp(op, l);
if (projection != null) {
options = options.projection(projection);
}
Optional<LongFunction<Integer>> limitFunction = op.getAsOptionalFunction("limit", Integer.class);
if (limitFunction.isPresent()) {
options = options.limit(limitFunction.get().apply(l));
}
Optional<LongFunction<Integer>> skipFunction = op.getAsOptionalFunction("skip", Integer.class);
if (skipFunction.isPresent()) {
options = options.skip(skipFunction.get().apply(l));
}
Optional<LongFunction<Boolean>> includeSimilarityFunction = op.getAsOptionalFunction("includeSimilarity", Boolean.class);
if (includeSimilarityFunction.isPresent()) {
options.includeSimilarity(includeSimilarityFunction.get().apply(l));
}
Optional<LongFunction<String>> pageStateFunction = op.getAsOptionalFunction("pageState", String.class);
if (pageStateFunction.isPresent()) {
options.pageState(pageStateFunction.get().apply(l));
}
return options;
}
@Override
public DataApiBaseOp getOp(long cycle) {
return opFunction.apply(cycle);
}
}
@@ -17,34 +17,36 @@
package io.nosqlbench.adapter.dataapi.opdispensers;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.core.query.Sort;
import com.datastax.astra.client.core.query.Filter;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionFindVectorOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionLegacyFindVectorFilterOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.function.LongFunction;
public class DataApiCollectionFindVectorOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionFindVectorOpDispenser.class);
private final LongFunction<DataApiCollectionFindVectorOp> opFunction;
public DataApiCollectionFindVectorOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
public class DataApiCollectionLegacyFindVectorFilterOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionLegacyFindVectorFilterOpDispenser.class);
private final LongFunction<DataApiCollectionLegacyFindVectorFilterOp> opFunction;
public DataApiCollectionLegacyFindVectorFilterOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionFindVectorOp> createOpFunction(ParsedOp op) {
private LongFunction<DataApiCollectionLegacyFindVectorFilterOp> createOpFunction(ParsedOp op) {
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
float[] vector = getVectorValues(op, l);
Filter filter = legacyGetFilterFromOp(op, l);
int limit = getLimit(op, l);
return new DataApiCollectionFindVectorOp(
return new DataApiCollectionLegacyFindVectorFilterOp(
db,
db.getCollection(targetFunction.apply(l)),
vector,
limit
limit,
filter
);
};
}
@@ -17,36 +17,34 @@
package io.nosqlbench.adapter.dataapi.opdispensers;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.core.query.Sort;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionFindVectorFilterOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionLegacyFindVectorOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.function.LongFunction;
public class DataApiCollectionFindVectorFilterOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionFindVectorFilterOpDispenser.class);
private final LongFunction<DataApiCollectionFindVectorFilterOp> opFunction;
public DataApiCollectionFindVectorFilterOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
public class DataApiCollectionLegacyFindVectorOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionLegacyFindVectorOpDispenser.class);
private final LongFunction<DataApiCollectionLegacyFindVectorOp> opFunction;
public DataApiCollectionLegacyFindVectorOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionFindVectorFilterOp> createOpFunction(ParsedOp op) {
private LongFunction<DataApiCollectionLegacyFindVectorOp> createOpFunction(ParsedOp op) {
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
float[] vector = getVectorValues(op, l);
Filter filter = getFilterFromOp(op, l);
int limit = getLimit(op, l);
return new DataApiCollectionFindVectorFilterOp(
return new DataApiCollectionLegacyFindVectorOp(
db,
db.getCollection(targetFunction.apply(l)),
vector,
limit,
filter
limit
);
};
}
@@ -0,0 +1,81 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.opdispensers;
import com.datastax.astra.client.collections.definition.documents.Document;
import com.datastax.astra.client.collections.commands.options.CollectionInsertManyOptions;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionInsertManyOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.LongFunction;
public class DataApiCollectionLegacyInsertManyOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionLegacyInsertManyOpDispenser.class);
private final LongFunction<DataApiCollectionInsertManyOp> opFunction;
public DataApiCollectionLegacyInsertManyOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionInsertManyOp> createOpFunction(ParsedOp op) {
return (l) -> {
List<Document> documents = new ArrayList<>();
op.getAsRequiredFunction("documents", List.class).apply(l).forEach(o -> documents.add(Document.parse(o.toString())));
return new DataApiCollectionInsertManyOp(
spaceFunction.apply(l).getDatabase(),
targetFunction.apply(l),
documents,
getCollectionInsertManyOptions(op, l)
);
};
}
private CollectionInsertManyOptions getCollectionInsertManyOptions(ParsedOp op, long l) {
CollectionInsertManyOptions options = new CollectionInsertManyOptions();
Optional<LongFunction<Map>> optionsFunction = op.getAsOptionalFunction("options", Map.class);
if (optionsFunction.isPresent()) {
Map<String, String> optionFields = optionsFunction.get().apply(l);
for(Map.Entry<String,String> entry: optionFields.entrySet()) {
switch(entry.getKey()) {
case "chunkSize"->
options = options.chunkSize(Integer.parseInt(entry.getValue()));
case "concurrency" ->
options = options.concurrency(Integer.parseInt(entry.getValue()));
case "ordered" ->
options = options.ordered(Boolean.parseBoolean(entry.getValue()));
case "timeout" ->
options = options.timeout(Integer.parseInt(entry.getValue()));
}
}
}
return options;
}
@Override
public DataApiBaseOp getOp(long cycle) {
return opFunction.apply(cycle);
}
}
@@ -19,8 +19,7 @@ package io.nosqlbench.adapter.dataapi.opdispensers;
import com.datastax.astra.client.collections.definition.documents.Document;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionInsertOneOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionInsertOneVectorOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionLegacyInsertOneVectorOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -28,25 +27,24 @@ import org.apache.logging.log4j.Logger;
import java.util.Map;
import java.util.function.LongFunction;
public class DataApiCollectionInsertOneVectorOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionInsertOneVectorOpDispenser.class);
private final LongFunction<DataApiCollectionInsertOneVectorOp> opFunction;
public class DataApiCollectionLegacyInsertOneVectorOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionLegacyInsertOneVectorOpDispenser.class);
private final LongFunction<DataApiCollectionLegacyInsertOneVectorOp> opFunction;
public DataApiCollectionInsertOneVectorOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
public DataApiCollectionLegacyInsertOneVectorOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionInsertOneVectorOp> createOpFunction(ParsedOp op) {
private LongFunction<DataApiCollectionLegacyInsertOneVectorOp> createOpFunction(ParsedOp op) {
LongFunction<Map> docMapFunc = op.getAsRequiredFunction("document", Map.class);
LongFunction<Document> docFunc = (long m) -> new Document(docMapFunc.apply(m));
LongFunction<float[]> vectorF= op.getAsRequiredFunction("vector", float[].class);
return (l) -> {
return new DataApiCollectionInsertOneVectorOp(
return new DataApiCollectionLegacyInsertOneVectorOp(
spaceFunction.apply(l).getDatabase(),
targetFunction.apply(l),
docFunc.apply(l),
vectorF.apply(l)
getVectorValues(op, l)
);
};
}
@@ -0,0 +1,92 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.opdispensers;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.core.query.Projection;
import com.datastax.astra.client.core.query.Sort;
import com.datastax.astra.client.collections.commands.ReturnDocument;
import com.datastax.astra.client.collections.commands.options.CollectionReplaceOneOptions;
import com.datastax.astra.client.collections.definition.documents.Document;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionLegacyReplaceOneOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Map;
import java.util.Optional;
import java.util.function.LongFunction;
public class DataApiCollectionLegacyReplaceOneOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionLegacyReplaceOneOpDispenser.class);
private final LongFunction<DataApiCollectionLegacyReplaceOneOp> opFunction;
public DataApiCollectionLegacyReplaceOneOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionLegacyReplaceOneOp> createOpFunction(ParsedOp op) {
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
Filter filter = legacyGetFilterFromOp(op, l);
CollectionReplaceOneOptions options = getCollectionReplaceOneOptions(op, l);
LongFunction<Map> docMapFunc = op.getAsRequiredFunction("document", Map.class);
LongFunction<Document> docFunc = (long m) -> new Document(docMapFunc.apply(m));
return new DataApiCollectionLegacyReplaceOneOp(
db,
db.getCollection(targetFunction.apply(l)),
filter,
docFunc.apply(l),
options
);
};
}
private CollectionReplaceOneOptions getCollectionReplaceOneOptions(ParsedOp op, long l) {
CollectionReplaceOneOptions options = new CollectionReplaceOneOptions();
Sort[] sorts = legacyGetSortFromOp(op, l);
if (sorts != null) {
options = options.sort(sorts);
}
Projection[] projection = getProjectionFromOp(op, l);
if (projection != null) {
options = options.projection(projection);
}
Optional<LongFunction<Boolean>> upsertFunction = op.getAsOptionalFunction("upsert", Boolean.class);
if (upsertFunction.isPresent()) {
options = options.upsert(upsertFunction.get().apply(l));
}
if (op.isDefined("returnDocument")) {
options = switch ((String) op.get("returnDocument", l)) {
case "after" -> options.returnDocument(ReturnDocument.AFTER);
case "before" -> options.returnDocument(ReturnDocument.BEFORE);
default -> throw new RuntimeException("Invalid returnDocument value: " + op.get("returnDocument", l));
};
}
return options;
}
@Override
public DataApiBaseOp getOp(long cycle) {
return opFunction.apply(cycle);
}
}
@@ -18,11 +18,11 @@ package io.nosqlbench.adapter.dataapi.opdispensers;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.collections.commands.options.CollectionReplaceOneOptions;
import com.datastax.astra.client.collections.definition.documents.Document;
import com.datastax.astra.client.collections.commands.Update;
import com.datastax.astra.client.collections.commands.options.CollectionUpdateManyOptions;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionReplaceOneOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionUpdateManyOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -31,40 +31,39 @@ import java.util.Map;
import java.util.Optional;
import java.util.function.LongFunction;
public class DataApiCollectionReplaceOneOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionReplaceOneOpDispenser.class);
private final LongFunction<DataApiCollectionReplaceOneOp> opFunction;
public class DataApiCollectionLegacyUpdateManyOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionLegacyUpdateManyOpDispenser.class);
private final LongFunction<DataApiCollectionUpdateManyOp> opFunction;
public DataApiCollectionReplaceOneOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
public DataApiCollectionLegacyUpdateManyOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionReplaceOneOp> createOpFunction(ParsedOp op) {
private LongFunction<DataApiCollectionUpdateManyOp> createOpFunction(ParsedOp op) {
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
Filter filter = getFilterFromOp(op, l);
CollectionReplaceOneOptions options = getCollectionReplaceOneOptions(op, l);
LongFunction<Map> docMapFunc = op.getAsRequiredFunction("document", Map.class);
LongFunction<Document> docFunc = (long m) -> new Document(docMapFunc.apply(m));
Filter filter = legacyGetFilterFromOp(op, l);
CollectionUpdateManyOptions options = getCollectionUpdateManyOptions(op, l);
LongFunction<Map> docMapFunc = op.getAsRequiredFunction("updates", Map.class);
return new DataApiCollectionReplaceOneOp(
return new DataApiCollectionUpdateManyOp(
db,
db.getCollection(targetFunction.apply(l)),
filter,
docFunc.apply(l),
new Update(docMapFunc.apply(l)),
options
);
};
}
private CollectionReplaceOneOptions getCollectionReplaceOneOptions(ParsedOp op, long l) {
CollectionReplaceOneOptions options = new CollectionReplaceOneOptions();
private CollectionUpdateManyOptions getCollectionUpdateManyOptions(ParsedOp op, long l) {
CollectionUpdateManyOptions options = new CollectionUpdateManyOptions();
Optional<LongFunction<Boolean>> upsertFunction = op.getAsOptionalFunction("upsert", Boolean.class);
if (upsertFunction.isPresent()) {
options = options.upsert(upsertFunction.get().apply(l));
}
return options;
}
@@ -0,0 +1,78 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.opdispensers;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.collections.commands.options.CollectionUpdateOneOptions;
import com.datastax.astra.client.core.query.Sort;
import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.collections.commands.Update;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCollectionUpdateOneOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Map;
import java.util.Optional;
import java.util.function.LongFunction;
public class DataApiCollectionLegacyUpdateOneOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCollectionLegacyUpdateOneOpDispenser.class);
private final LongFunction<DataApiCollectionUpdateOneOp> opFunction;
public DataApiCollectionLegacyUpdateOneOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCollectionUpdateOneOp> createOpFunction(ParsedOp op) {
return (l) -> {
Database db = spaceFunction.apply(l).getDatabase();
Filter filter = legacyGetFilterFromOp(op, l);
CollectionUpdateOneOptions options = getCollectionUpdateOneOptions(op, l);
LongFunction<Map> docMapFunc = op.getAsRequiredFunction("update", Map.class);
return new DataApiCollectionUpdateOneOp(
db,
db.getCollection(targetFunction.apply(l)),
filter,
new Update(docMapFunc.apply(l)),
options
);
};
}
private CollectionUpdateOneOptions getCollectionUpdateOneOptions(ParsedOp op, long l) {
CollectionUpdateOneOptions options = new CollectionUpdateOneOptions();
Sort[] sorts = legacyGetSortFromOp(op, l);
if (sorts != null) {
options = options.sort(sorts);
}
Optional<LongFunction<Boolean>> upsertFunction = op.getAsOptionalFunction("upsert", Boolean.class);
if (upsertFunction.isPresent()) {
options = options.upsert(upsertFunction.get().apply(l));
}
return options;
}
@Override
public DataApiBaseOp getOp(long cycle) {
return opFunction.apply(cycle);
}
}
@@ -27,8 +27,6 @@ import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Map;
import java.util.Optional;
import java.util.function.LongFunction;
public class DataApiCollectionUpdateManyOpDispenser extends DataApiOpDispenser {
@@ -45,13 +43,13 @@ public class DataApiCollectionUpdateManyOpDispenser extends DataApiOpDispenser {
Database db = spaceFunction.apply(l).getDatabase();
Filter filter = getFilterFromOp(op, l);
CollectionUpdateManyOptions options = getCollectionUpdateManyOptions(op, l);
LongFunction<Map> docMapFunc = op.getAsRequiredFunction("updates", Map.class);
Update update = getUpdateFromOp(op, l);
return new DataApiCollectionUpdateManyOp(
db,
db.getCollection(targetFunction.apply(l)),
filter,
new Update(docMapFunc.apply(l)),
update,
options
);
};
@@ -59,11 +57,10 @@ public class DataApiCollectionUpdateManyOpDispenser extends DataApiOpDispenser {
private CollectionUpdateManyOptions getCollectionUpdateManyOptions(ParsedOp op, long l) {
CollectionUpdateManyOptions options = new CollectionUpdateManyOptions();
Optional<LongFunction<Boolean>> upsertFunction = op.getAsOptionalFunction("upsert", Boolean.class);
if (upsertFunction.isPresent()) {
options = options.upsert(upsertFunction.get().apply(l));
Boolean upsert = getUpsertFromOp(op, l);
if (upsert != null) {
options = options.upsert(upsert);
}
return options;
}
@@ -46,13 +46,13 @@ public class DataApiCollectionUpdateOneOpDispenser extends DataApiOpDispenser {
Database db = spaceFunction.apply(l).getDatabase();
Filter filter = getFilterFromOp(op, l);
CollectionUpdateOneOptions options = getCollectionUpdateOneOptions(op, l);
LongFunction<Map> docMapFunc = op.getAsRequiredFunction("update", Map.class);
Update update = getUpdateFromOp(op, l);
return new DataApiCollectionUpdateOneOp(
db,
db.getCollection(targetFunction.apply(l)),
filter,
new Update(docMapFunc.apply(l)),
update,
options
);
};
@@ -60,23 +60,17 @@ public class DataApiCollectionUpdateOneOpDispenser extends DataApiOpDispenser {
private CollectionUpdateOneOptions getCollectionUpdateOneOptions(ParsedOp op, long l) {
CollectionUpdateOneOptions options = new CollectionUpdateOneOptions();
Sort sort = getSortFromOp(op, l);
float[] vector = getVectorFromOp(op, l);
Optional<LongFunction<Boolean>> upsertFunction = op.getAsOptionalFunction("upsert", Boolean.class);
if (upsertFunction.isPresent()) {
options = options.upsert(upsertFunction.get().apply(l));
Sort[] sorts = getSortFromOp(op, l);
Boolean upsert = getUpsertFromOp(op, l);
if (sorts != null) {
options = options.sort(sorts);
}
if (sort != null) {
options = (vector != null) ? options.sort(Sort.vector(vector), sort) : options.sort(sort);
if ( upsert != null ){
options = options.upsert(upsert);
}
return options;
}
private float[] getVectorFromOp(ParsedOp op, long l) {
return getVectorValues(op.get("vector", l));
}
@Override
public DataApiBaseOp getOp(long cycle) {
return opFunction.apply(cycle);
@@ -18,33 +18,32 @@ package io.nosqlbench.adapter.dataapi.opdispensers;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCreateCollectionOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiDbCreateCollectionOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Optional;
import java.util.function.LongFunction;
public class DataApiCreateCollectionOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCreateCollectionOpDispenser.class);
private final LongFunction<DataApiCreateCollectionOp> opFunction;
public class DataApiDbCreateCollectionOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiDbCreateCollectionOpDispenser.class);
private final LongFunction<DataApiDbCreateCollectionOp> opFunction;
public DataApiCreateCollectionOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
public DataApiDbCreateCollectionOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCreateCollectionOp> createOpFunction(ParsedOp op) {
private LongFunction<DataApiDbCreateCollectionOp> createOpFunction(ParsedOp op) {
return (l) -> {
DataApiCreateCollectionOp dataApiCreateCollectionOp =
new DataApiCreateCollectionOp(
DataApiDbCreateCollectionOp dataApiDbCreateCollectionOp =
new DataApiDbCreateCollectionOp(
spaceFunction.apply(l).getDatabase(),
targetFunction.apply(l),
this.getCollectionDefinitionFromOp(op, l)
);
return dataApiCreateCollectionOp;
return dataApiDbCreateCollectionOp;
};
}
@@ -18,23 +18,23 @@ package io.nosqlbench.adapter.dataapi.opdispensers;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiDropCollectionOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiLegacyDeleteCollectionOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.function.LongFunction;
public class DataApiDropCollectionOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiDropCollectionOpDispenser.class);
private final LongFunction<DataApiDropCollectionOp> opFunction;
public DataApiDropCollectionOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
public class DataApiDbDeleteCollectionOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiDbDeleteCollectionOpDispenser.class);
private final LongFunction<DataApiLegacyDeleteCollectionOp> opFunction;
public DataApiDbDeleteCollectionOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiDropCollectionOp> createOpFunction(ParsedOp op) {
return (l) -> new DataApiDropCollectionOp(
private LongFunction<DataApiLegacyDeleteCollectionOp> createOpFunction(ParsedOp op) {
return (l) -> new DataApiLegacyDeleteCollectionOp(
spaceFunction.apply(l).getDatabase(),
targetFunction.apply(l)
);
@@ -0,0 +1,56 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.opdispensers;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiLegacyCreateCollectionOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.function.LongFunction;
public class DataApiLegacyCreateCollectionOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiLegacyCreateCollectionOpDispenser.class);
private final LongFunction<DataApiLegacyCreateCollectionOp> opFunction;
public DataApiLegacyCreateCollectionOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiLegacyCreateCollectionOp> createOpFunction(ParsedOp op) {
return (l) -> {
DataApiLegacyCreateCollectionOp dataApiCreateCollectionOp =
new DataApiLegacyCreateCollectionOp(
spaceFunction.apply(l).getDatabase(),
targetFunction.apply(l),
this.legacyGetCollectionDefinitionFromOp(op, l)
);
return dataApiCreateCollectionOp;
};
}
@Override
public DataApiBaseOp getOp(long cycle) {
return opFunction.apply(cycle);
}
}
@@ -18,27 +18,27 @@ package io.nosqlbench.adapter.dataapi.opdispensers;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiCreateCollectionWithClassOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiLegacyCreateCollectionWithClassOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.function.LongFunction;
public class DataApiCreateCollectionWithClassOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiCreateCollectionWithClassOpDispenser.class);
private final LongFunction<DataApiCreateCollectionWithClassOp> opFunction;
public class DataApiLegacyCreateCollectionWithClassOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiLegacyCreateCollectionWithClassOpDispenser.class);
private final LongFunction<DataApiLegacyCreateCollectionWithClassOp> opFunction;
public DataApiCreateCollectionWithClassOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
public DataApiLegacyCreateCollectionWithClassOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiCreateCollectionWithClassOp> createOpFunction(ParsedOp op) {
return (l) -> new DataApiCreateCollectionWithClassOp(
private LongFunction<DataApiLegacyCreateCollectionWithClassOp> createOpFunction(ParsedOp op) {
return (l) -> new DataApiLegacyCreateCollectionWithClassOp(
spaceFunction.apply(l).getDatabase(),
targetFunction.apply(l),
this.getCollectionDefinitionFromOp(op, l),
this.legacyGetCollectionDefinitionFromOp(op, l),
getCreateClass(op, l)
);
}
@@ -0,0 +1,47 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.opdispensers;
import io.nosqlbench.adapter.dataapi.DataApiDriverAdapter;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapter.dataapi.ops.DataApiLegacyDeleteCollectionOp;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.function.LongFunction;
public class DataApiLegacyDeleteCollectionOpDispenser extends DataApiOpDispenser {
private static final Logger logger = LogManager.getLogger(DataApiLegacyDeleteCollectionOpDispenser.class);
private final LongFunction<DataApiLegacyDeleteCollectionOp> opFunction;
public DataApiLegacyDeleteCollectionOpDispenser(DataApiDriverAdapter adapter, ParsedOp op, LongFunction<String> targetFunction) {
super(adapter, op, targetFunction);
this.opFunction = createOpFunction(op);
}
private LongFunction<DataApiLegacyDeleteCollectionOp> createOpFunction(ParsedOp op) {
return (l) -> new DataApiLegacyDeleteCollectionOp(
spaceFunction.apply(l).getDatabase(),
targetFunction.apply(l)
);
}
@Override
public DataApiBaseOp getOp(long cycle) {
return opFunction.apply(cycle);
}
}
@@ -20,12 +20,18 @@ import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.core.query.Filters;
import com.datastax.astra.client.collections.definition.CollectionDefinition;
import com.datastax.astra.client.collections.definition.CollectionDefaultIdTypes;
import com.datastax.astra.client.collections.definition.documents.Document;
import com.datastax.astra.client.collections.commands.ReturnDocument;
import com.datastax.astra.client.collections.commands.Update;
import com.datastax.astra.client.collections.commands.Updates;
import com.datastax.astra.client.core.hybrid.Hybrid;
import com.datastax.astra.client.core.query.Sort;
import com.datastax.astra.client.core.rerank.RerankServiceOptions;
import com.datastax.astra.client.core.vector.DataAPIVector;
import com.datastax.astra.client.core.vector.SimilarityMetric;
import com.datastax.astra.client.core.query.Projection;
import io.nosqlbench.adapter.dataapi.DataApiSpace;
import io.nosqlbench.nb.api.errors.OpConfigError;
import io.nosqlbench.adapter.dataapi.ops.DataApiBaseOp;
import io.nosqlbench.adapters.api.activityimpl.BaseOpDispenser;
import io.nosqlbench.adapters.api.activityimpl.uniform.DriverAdapter;
@@ -33,6 +39,8 @@ import io.nosqlbench.adapters.api.templating.ParsedOp;
import java.util.*;
import java.util.function.LongFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public abstract class DataApiOpDispenser extends BaseOpDispenser<DataApiBaseOp, DataApiSpace> {
protected final LongFunction<String> targetFunction;
@@ -45,108 +53,101 @@ public abstract class DataApiOpDispenser extends BaseOpDispenser<DataApiBaseOp,
this.spaceFunction = adapter.getSpaceFunc(op);
}
protected Sort getSortFromOp(ParsedOp op, long l) {
Sort sort = null;
protected Sort[] getSortFromOp(ParsedOp op, long l) {
List<Sort> sorts = null;
long sortKeyCount = Stream.of("sort", "vector", "vectorize").filter(op::isDefined).count();
if (sortKeyCount > 1) {
throw new OpConfigError(
"Can sort by only one of: 'sort' (regular asc/desc), 'vector', 'vectorize' in an op."
);
}
Optional<LongFunction<Map>> sortFunction = op.getAsOptionalFunction("sort", Map.class);
if (sortFunction.isPresent()) {
@SuppressWarnings("unchecked")
Map<String,Object> sortFields = sortFunction.get().apply(l);
String sortOrder = sortFields.get("type").toString();
String sortField = sortFields.get("field").toString();
switch(sortOrder) {
case "asc" -> sort = Sort.ascending(sortField);
case "desc" -> sort = Sort.descending(sortField);
sorts = sortFields.entrySet().stream()
.map(e -> {
String field = e.getKey();
String sortOrder = String.valueOf(e.getValue()).trim();
if (sortOrder.equalsIgnoreCase("asc") || sortOrder.equalsIgnoreCase("ascending")) {
return Sort.ascending(field);
} else if (sortOrder.equalsIgnoreCase("desc") || sortOrder.equalsIgnoreCase("descending")) {
return Sort.descending(field);
} else {
throw new OpConfigError(
"Invalid sort order '" + sortOrder + "' for field '" + field +
"'; expected 'asc' or 'desc' (case-insensitive)."
);
}
})
.collect(Collectors.toList());
}
if (op.isDefined("vector")) {
float[] vector = getVectorValues(op, l);
if (vector != null) {
// TODO use DataAPIVector as soon as the client allows here:
sorts = List.of(Sort.vector(vector));
}
}
return sort;
if (op.isDefined("vectorize")) {
Optional<LongFunction<String>> vzeFunction = op.getAsOptionalFunction("vectorize", String.class);
if (vzeFunction.isPresent()){
String vectorize = vzeFunction.get().apply(l);
sorts = List.of(Sort.vectorize(vectorize));
}
}
if (sorts != null) {
return sorts.toArray(new Sort[0]);
}
return null;
}
protected Filter getFilterFromOp(ParsedOp op, long l) {
// TODO: Clarify 'filter' vs 'filters' or whether to support both uniformly
Filter filter = null;
Optional<LongFunction<List>> filterFunction = op.getAsOptionalFunction("filters", List.class)
.or(() -> op.getAsOptionalFunction("filter",List.class));
if (filterFunction.isPresent()) {
List<Map<String,Object>> filters = filterFunction.get().apply(l);
List<Filter> andFilterList = new ArrayList<>();
List<Filter> orFilterList = new ArrayList<>();
for (Map<String,Object> filterFields : filters) {
switch ((String)filterFields.get("conjunction")) {
case "and" ->
addOperatorFilter(andFilterList, filterFields.get("operator").toString(), filterFields.get("field").toString(), filterFields.get("value"));
case "or" ->
addOperatorFilter(orFilterList, filterFields.get("operator").toString(), filterFields.get("field").toString(), filterFields.get("value"));
default -> logger.error(() -> "Conjunction " + filterFields.get("conjunction") + " not supported");
}
}
if (!andFilterList.isEmpty())
filter = Filters.and(andFilterList.toArray(new Filter[0]));
if (!orFilterList.isEmpty())
filter = Filters.or(orFilterList.toArray(new Filter[0]));
Map<String, Object> filterMap = getFreeFormFromOp(op, l, "filter", false);
if (filterMap != null) {
return new Filter(filterMap);
}
return filter;
return null;
}
protected void addOperatorFilter(List<Filter> filtersList, String operator, String fieldName, Object fieldValue) {
switch (operator) {
case "all" ->
filtersList.add(Filters.all(fieldName, fieldValue));
case "eq" ->
filtersList.add(Filters.eq(fieldName, fieldValue));
case "exists" -> {
if (fieldValue != null) {
logger.warn(() -> "'exists' operator does not support value field");
}
filtersList.add(Filters.exists(fieldName));
}
case "gt" ->
filtersList.add(Filters.gt(fieldName, (long) fieldValue));
case "gte" ->
filtersList.add(Filters.gte(fieldName, (long) fieldValue));
case "hasSize" ->
filtersList.add(Filters.hasSize(fieldName, (int) fieldValue));
case "in" ->
filtersList.add(Filters.in(fieldName, fieldValue));
case "lt" ->
filtersList.add(Filters.lt(fieldName, (long) fieldValue));
case "lte" ->
filtersList.add(Filters.lte(fieldName, (long) fieldValue));
case "ne" ->
filtersList.add(Filters.ne(fieldName, fieldValue));
case "nin" ->
filtersList.add(Filters.nin(fieldName, fieldValue));
default -> logger.error(() -> "Operation '" + operator + "' not supported");
}
protected Document getReplacementFromOp(ParsedOp op, long l) {
Map<String, Object> docMap = getFreeFormFromOp(op, l, "replacement", true);
return new Document(docMap);
}
protected Update getUpdates(ParsedOp op, long l) {
Update update = new Update();
Optional<LongFunction<Map>> updatesFunction = op.getAsOptionalFunction("updates", Map.class);
if (updatesFunction.isPresent()) {
Map<String, Object> updates = updatesFunction.get().apply(l);
for (Map.Entry<String, Object> entry : updates.entrySet()) {
if (entry.getKey().equalsIgnoreCase("update")) {
Map<String, Object> updateFields = (Map<String, Object>) entry.getValue();
switch (updateFields.get("operation").toString()) {
case "set" ->
update = Updates.set(updateFields.get("field").toString(), updateFields.get("value"));
case "inc" ->
update = Updates.inc(updateFields.get("field").toString(), (double) updateFields.get("value"));
case "unset" -> update = Updates.unset(updateFields.get("field").toString());
case "addToSet" ->
update = Updates.addToSet(updateFields.get("field").toString(), updateFields.get("value"));
case "min" ->
update = Updates.min(updateFields.get("field").toString(), (double) updateFields.get("value"));
case "rename" ->
update = Updates.rename(updateFields.get("field").toString(), updateFields.get("value").toString());
default -> logger.error(() -> "Operation " + updateFields.get("operation") + " not supported");
}
} else {
logger.error(() -> "Filter " + entry.getKey() + " not supported");
}
}
protected Document getDocumentFromRawMap(Map<String, Object> docMap) {
Document doc = new Document(docMap);
// if docMap has a '$vector' key, invoke:
if (docMap.containsKey("$vector")) {
doc.vector(new DataAPIVector(getVectorValues(docMap.get("$vector"))));
}
return update;
return doc;
}
protected Document getDocumentFromOp(ParsedOp op, long l) {
Map<String, Object> docMap = getFreeFormFromOp(op, l, "document", true);
return getDocumentFromRawMap(docMap);
}
protected List<Document> getDocumentsFromOp(ParsedOp op, long l) {
List<Map<String, Object>> docMapList = getFreeFormListFromOp(op, l, "documents", true);
return docMapList.stream().map((docMap) -> getDocumentFromRawMap(docMap)).toList();
}
protected Update getUpdateFromOp(ParsedOp op, long l) {
Map<String, Object> updateMap = getFreeFormFromOp(op, l, "update", true);
return new Update(updateMap);
}
protected Map<String, Object> getCollectionDefinitionFromOp(ParsedOp op, long l) {
Map<String, Object> definition = getFreeFormFromOp(op, l, "definition", true);
return definition;
}
protected float[] getVectorValues(ParsedOp op, long l) {
@@ -167,6 +168,8 @@ public abstract class DataApiOpDispenser extends BaseOpDispenser<DataApiBaseOp,
}
} else if (rawVectorValues instanceof List) {
return getVectorValuesList(rawVectorValues);
} else if (rawVectorValues == null) {
throw new RuntimeException("Invalid specification for values (null)");
} else {
throw new RuntimeException("Invalid type specified for values (type: " + rawVectorValues.getClass().getSimpleName() + "), values: " + rawVectorValues.toString());
}
@@ -175,6 +178,7 @@ public abstract class DataApiOpDispenser extends BaseOpDispenser<DataApiBaseOp,
protected float[] getVectorValuesList(Object rawVectorValues) {
float[] vectorValues = null;
@SuppressWarnings("unchecked")
List<Object> vectorValuesList = (List<Object>) rawVectorValues;
vectorValues = new float[vectorValuesList.size()];
for (int i = 0; i < vectorValuesList.size(); i++) {
@@ -184,30 +188,418 @@ public abstract class DataApiOpDispenser extends BaseOpDispenser<DataApiBaseOp,
}
protected Projection[] getProjectionFromOp(ParsedOp op, long l) {
Projection[] projection = null;
Optional<LongFunction<Map>> projectionFunction = op.getAsOptionalFunction("projection", Map.class);
if (projectionFunction.isPresent()) {
Map<String,List<String>> projectionFields = projectionFunction.get().apply(l);
for (Map.Entry<String,List<String>> field : projectionFields.entrySet()) {
List<String> includeFields = field.getValue();
StringBuffer sb = new StringBuffer();
for (String includeField : includeFields) {
sb.append(includeField).append(",");
}
sb.deleteCharAt(sb.length() - 1);
if (projectionFunction.isEmpty()) {
return null;
}
@SuppressWarnings("unchecked")
Map<String, List<String>> projectionFields = projectionFunction.get().apply(l);
return projectionFields.entrySet().stream()
.flatMap(field -> {
String[] arr = field.getValue().toArray(new String[0]);
if (field.getKey().equalsIgnoreCase("include")) {
projection = Projection.include(sb.toString());
return Arrays.stream(Projection.include(arr));
} else if (field.getKey().equalsIgnoreCase("exclude")) {
projection = Projection.exclude(sb.toString());
return Arrays.stream(Projection.exclude(arr));
} else {
logger.error("Projection " + field + " not supported");
logger.error("Projection directive '" + field.getKey() + "' not supported");
return Stream.<Projection>empty();
}
}).toArray(Projection[]::new);
}
protected Boolean getUpsertFromOp(ParsedOp op, long l) {
Optional<LongFunction<Boolean>> upsertFunction = op.getAsOptionalFunction("upsert", Boolean.class);
if (upsertFunction.isPresent()) {
LongFunction<Boolean> uf = upsertFunction.get();
return uf.apply(l);
}
return null;
}
protected Integer getChunkSizeFromOp(ParsedOp op, long l) {
Optional<LongFunction<Integer>> csFunction = op.getAsOptionalFunction("chunk_size", Integer.class);
if (csFunction.isPresent()) {
LongFunction<Integer> cs = csFunction.get();
return cs.apply(l);
}
return null;
}
protected Boolean getOrderedFromOp(ParsedOp op, long l) {
Optional<LongFunction<Boolean>> orderedFunction = op.getAsOptionalFunction("ordered", Boolean.class);
if (orderedFunction.isPresent()) {
LongFunction<Boolean> of = orderedFunction.get();
return of.apply(l);
}
return null;
}
protected ReturnDocument getReturnDocumentFromOp(ParsedOp op, long l) {
Optional<LongFunction<String>> rdf = op.getAsOptionalFunction("return_document", String.class);
if (rdf.isPresent()) {
String rdValue = rdf.get().apply(l);
return switch (rdValue) {
case "after" -> ReturnDocument.AFTER;
case "before" -> ReturnDocument.BEFORE;
default -> throw new RuntimeException("Invalid returnDocument value: " + op.get("return_document", l));
};
}
return null;
}
protected Optional<Boolean> getIncludeSimilarityFromOp(ParsedOp op, long l) {
Optional<LongFunction<Boolean>> includeSimFunction = op.getAsOptionalFunction("include_similarity", Boolean.class);
if (includeSimFunction.isPresent()) {
LongFunction<Boolean> sf = includeSimFunction.get();
return Optional.of(sf.apply(l));
}
return Optional.empty();
}
protected Optional<Boolean> getIncludeSortVectorFromOp(ParsedOp op, long l) {
Optional<LongFunction<Boolean>> includeSvFunction = op.getAsOptionalFunction("include_sort_vector", Boolean.class);
if (includeSvFunction.isPresent()) {
LongFunction<Boolean> sv = includeSvFunction.get();
return Optional.of(sv.apply(l));
}
return Optional.empty();
}
protected Optional<Integer> getLimitFromOp(ParsedOp op, long l) {
Optional<LongFunction<Integer>> limitFunction = op.getAsOptionalFunction("limit", Integer.class);
if (limitFunction.isPresent()) {
LongFunction<Integer> lf = limitFunction.get();
return Optional.of(lf.apply(l));
}
return Optional.empty();
}
protected Optional<Integer> getSkipFromOp(ParsedOp op, long l) {
Optional<LongFunction<Integer>> skipFunction = op.getAsOptionalFunction("skip", Integer.class);
if (skipFunction.isPresent()) {
LongFunction<Integer> sf = skipFunction.get();
return Optional.of(sf.apply(l));
}
return Optional.empty();
}
@SuppressWarnings("unchecked")
protected Map<String, Object> getFreeFormFromOp(ParsedOp op, long l, String fieldName, Boolean required) {
Optional<LongFunction<Map>> ffMapFunc = op.getAsOptionalFunction(fieldName, Map.class);
if (ffMapFunc.isPresent()) {
LongFunction<Map> dmf = ffMapFunc.get();
return dmf.apply(l);
} else {
if (required) {
throw new OpConfigError(
"Required field '" + fieldName + "' not supplied."
);
}
return null;
}
}
@SuppressWarnings("unchecked")
protected List<Map<String, Object>> getFreeFormListFromOp(ParsedOp op, long l, String fieldName, Boolean required) {
Optional<LongFunction<List>> ffMapFunc = op.getAsOptionalFunction(fieldName, List.class);
if (ffMapFunc.isPresent()) {
LongFunction<List> dmf = ffMapFunc.get();
return dmf.apply(l);
} else {
if (required) {
throw new OpConfigError(
"Required field '" + fieldName + "' not supplied."
);
}
return null;
}
}
protected Optional<Boolean> getIncludeScoresFromOp(ParsedOp op, long l) {
Optional<LongFunction<Boolean>> includeScFunction = op.getAsOptionalFunction("include_scores", Boolean.class);
if (includeScFunction.isPresent()) {
LongFunction<Boolean> isf = includeScFunction.get();
return Optional.of(isf.apply(l));
}
return Optional.empty();
}
protected Optional<String> getRerankQueryFromOp(ParsedOp op, long l) {
Optional<LongFunction<String>> rqf = op.getAsOptionalFunction("rerank_query", String.class);
if (rqf.isPresent()) {
String rqValue = rqf.get().apply(l);
return Optional.of(rqValue);
}
return Optional.empty();
}
protected Optional<String> getRerankOnFromOp(ParsedOp op, long l) {
Optional<LongFunction<String>> rof = op.getAsOptionalFunction("rerank_on", String.class);
if (rof.isPresent()) {
String roValue = rof.get().apply(l);
return Optional.of(roValue);
}
return Optional.empty();
}
@SuppressWarnings("unchecked")
protected Optional<Object> getHybridLimitsFromOp(ParsedOp op, long l) {
Optional<LongFunction<Object>> hlFunc = op.getAsOptionalFunction("hybrid_limits", Object.class);
if (hlFunc.isPresent()) {
Object hlValue = hlFunc.get().apply(l);
if (hlValue instanceof Integer || hlValue instanceof Long) {
return Optional.of(hlValue);
} else if (hlValue instanceof Map<?, ?> rawMap) {
return Optional.of((Map<String, Object>) rawMap);
} else {
throw new OpConfigError(
"'hybrid_limits' must be an integer or a map, got: " + hlValue.getClass().getSimpleName()
);
}
}
return Optional.empty();
}
protected Optional<RerankServiceOptions> getRerankServiceFromOp(ParsedOp op, long l) {
Map<String, Object> rerankService = getFreeFormFromOp(op, l, "rerank", false);
if (rerankService != null) {
RerankServiceOptions rsOptions = new RerankServiceOptions();
if (rerankService.containsKey("provider")) {
rsOptions = rsOptions.provider((String) rerankService.get("provider"));
}
if (rerankService.containsKey("modelName")) {
rsOptions = rsOptions.modelName((String) rerankService.get("modelName"));
}
if (rerankService.containsKey("authentication")) {
rsOptions = rsOptions.authentication((Map<String, Object>) rerankService.get("authentication"));
}
if (rerankService.containsKey("parameters")) {
rsOptions = rsOptions.parameters((Map<String, Object>) rerankService.get("parameters"));
}
return Optional.of(rsOptions);
}
return Optional.empty();
}
protected Sort getFindAndRerankSortFromOp(ParsedOp op, long l) {
Map<String, Object> docMap = getFreeFormFromOp(op, l, "sort", true);
if (docMap.size() != 1 || !docMap.containsKey("$hybrid")) {
throw new OpConfigError("'sort' must contain exactly one key: '$hybrid'");
}
Object hybridValue = docMap.get("$hybrid");
if (hybridValue instanceof String hybridString) {
return Sort.hybrid(hybridString);
}
if (hybridValue instanceof Map<?, ?> rawMap) {
@SuppressWarnings("unchecked")
Map<String, Object> hybMap = (Map<String, Object>) rawMap;
boolean hasVectorize = hybMap.containsKey("$vectorize");
boolean hasVector = hybMap.containsKey("$vector");
if (!hasVectorize && !hasVector) {
throw new OpConfigError(
"'$hybrid' sub-object must contain at least one of '$vectorize' or '$vector'"
);
}
Set<String> allowedKeys = Set.of("$vectorize", "$vector", "$lexical");
for (String key : hybMap.keySet()) {
if (!allowedKeys.contains(key)) {
throw new OpConfigError("Unexpected key in '$hybrid' sub-object: '" + key + "'");
}
}
Hybrid hyb = new Hybrid();
if (hasVectorize) {
hyb = hyb.vectorize((String) hybMap.get("$vectorize"));
}
if (hasVector) {
hyb = hyb.vector(new DataAPIVector(getVectorValues(hybMap.get("$vector"))));
}
if (hybMap.containsKey("$lexical")) {
hyb = hyb.lexical((String) hybMap.get("$lexical"));
}
return Sort.hybrid(hyb);
}
throw new OpConfigError(
"'$hybrid' value must be a string or a sub-object, got: " + hybridValue.getClass().getSimpleName()
);
}
/* LEGACY OP DISPENSER UTILS START HERE */
/*
updates:
update:
operation: inc
field: "incd field"
value: 500
*/
protected Update legacyGetUpdateFromOp(ParsedOp op, long l) {
Update update = new Update();
Optional<LongFunction<Map>> updatesFunction = op.getAsOptionalFunction("updates", Map.class);
if (updatesFunction.isPresent()) {
@SuppressWarnings("unchecked")
Map<String, Object> updates = updatesFunction.get().apply(l);
for (Map.Entry<String, Object> entry : updates.entrySet()) {
if (entry.getKey().equalsIgnoreCase("update")) {
@SuppressWarnings("unchecked")
Map<String, Object> updateFields = (Map<String, Object>) entry.getValue();
switch (updateFields.get("operation").toString()) {
case "set" ->
update = Updates.set(updateFields.get("field").toString(), updateFields.get("value"));
case "inc" ->
update = Updates.inc(updateFields.get("field").toString(), ((Number) updateFields.get("value")).doubleValue());
case "unset" -> update = Updates.unset(updateFields.get("field").toString());
case "addToSet" ->
update = Updates.addToSet(updateFields.get("field").toString(), updateFields.get("value"));
case "min" ->
update = Updates.min(updateFields.get("field").toString(), ((Number) updateFields.get("value")).doubleValue());
case "rename" ->
update = Updates.rename(updateFields.get("field").toString(), updateFields.get("value").toString());
default -> logger.error(() -> "Operation " + updateFields.get("operation") + " not supported");
}
} else {
logger.error(() -> "Unsupported entry under 'updates': '" + entry.getKey() + "'");
}
}
}
return projection;
return update;
}
protected CollectionDefinition getCollectionDefinitionFromOp(ParsedOp op, long l) {
protected void legacyAddOperatorFilter(List<Filter> filtersList, String operator, String fieldName, Object fieldValue) {
switch (operator) {
case "all" ->
filtersList.add(Filters.all(fieldName, fieldValue));
case "eq" ->
filtersList.add(Filters.eq(fieldName, fieldValue));
case "exists" -> {
if (fieldValue != null) {
logger.warn(() -> "'exists' operator does not support value field");
}
filtersList.add(Filters.exists(fieldName));
}
case "gt" ->
filtersList.add(Filters.gt(fieldName, ((Number) fieldValue).longValue()));
case "gte" ->
filtersList.add(Filters.gte(fieldName, ((Number) fieldValue).longValue()));
case "hasSize" ->
filtersList.add(Filters.hasSize(fieldName, ((Number) fieldValue).intValue()));
case "in" ->
filtersList.add(Filters.in(fieldName, fieldValue));
case "lt" ->
filtersList.add(Filters.lt(fieldName, ((Number) fieldValue).longValue()));
case "lte" ->
filtersList.add(Filters.lte(fieldName, ((Number) fieldValue).longValue()));
case "ne" ->
filtersList.add(Filters.ne(fieldName, fieldValue));
case "nin" ->
filtersList.add(Filters.nin(fieldName, fieldValue));
default -> logger.error(() -> "Operation '" + operator + "' not supported");
}
}
/*
filters:
- conjunction: "and"
operator: "eq"
field: "field1"
value: 74
- conjunction: "and"
operator: "lt"
field: "field2"
value: 111
*/
protected Filter legacyGetFilterFromOp(ParsedOp op, long l) {
Filter filter = null;
Optional<LongFunction<List>> filterFunction = op.getAsOptionalFunction("filters", List.class)
.or(() -> op.getAsOptionalFunction("filter",List.class));
if (filterFunction.isPresent()) {
@SuppressWarnings("unchecked")
List<Map<String,Object>> filters = filterFunction.get().apply(l);
List<Filter> andFilterList = new ArrayList<>();
List<Filter> orFilterList = new ArrayList<>();
for (Map<String,Object> filterFields : filters) {
switch ((String)filterFields.get("conjunction")) {
case "and" ->
legacyAddOperatorFilter(andFilterList, filterFields.get("operator").toString(), filterFields.get("field").toString(), filterFields.get("value"));
case "or" ->
legacyAddOperatorFilter(orFilterList, filterFields.get("operator").toString(), filterFields.get("field").toString(), filterFields.get("value"));
default -> logger.error(() -> "Conjunction " + filterFields.get("conjunction") + " not supported");
}
}
if (!andFilterList.isEmpty() && !orFilterList.isEmpty()) {
throw new OpConfigError(
"filters list mixes 'and' and 'or' conjunctions, which is not supported; " +
"use only one conjunction type per filters list"
);
}
if (!andFilterList.isEmpty())
filter = Filters.and(andFilterList.toArray(new Filter[0]));
if (!orFilterList.isEmpty())
filter = Filters.or(orFilterList.toArray(new Filter[0]));
}
return filter;
}
/*
sort:
field: the_field
type: desc
*/
protected Sort[] legacyGetSortFromOp(ParsedOp op, long l) {
List<Sort> sorts = null;
long sortKeyCount = Stream.of("sort", "vector", "vectorize").filter(op::isDefined).count();
if (sortKeyCount > 1) {
throw new OpConfigError(
"Can sort by only one of: 'sort' (regular asc/desc), 'vector', 'vectorize' in an op."
);
}
Optional<LongFunction<Map>> sortFunction = op.getAsOptionalFunction("sort", Map.class);
if (sortFunction.isPresent()) {
@SuppressWarnings("unchecked")
Map<String,Object> sortFields = sortFunction.get().apply(l);
String sortOrder = sortFields.get("type").toString();
String sortField = sortFields.get("field").toString();
switch(sortOrder) {
case "asc" -> sorts = List.of(Sort.ascending(sortField));
case "desc" -> sorts = List.of(Sort.descending(sortField));
}
}
if (op.isDefined("vector")) {
float[] vector = getVectorValues(op, l);
if (vector != null) {
// TODO use DataAPIVector as soon as the client allows here:
sorts = List.of(Sort.vector(vector));
}
}
if (op.isDefined("vectorize")) {
Optional<LongFunction<String>> vzeFunction = op.getAsOptionalFunction("vectorize", String.class);
if (vzeFunction.isPresent()){
String vectorize = vzeFunction.get().apply(l);
sorts = List.of(Sort.vectorize(vectorize));
}
}
if (sorts != null) {
return sorts.toArray(new Sort[0]);
}
return null;
}
@SuppressWarnings("unchecked")
protected CollectionDefinition legacyGetCollectionDefinitionFromOp(ParsedOp op, long l) {
CollectionDefinition optionsBldr = new CollectionDefinition();
Optional<LongFunction<Integer>> dimFunc = op.getAsOptionalFunction("dimensions", Integer.class);
if (dimFunc.isPresent()) {
@@ -237,19 +629,24 @@ public abstract class DataApiOpDispenser extends BaseOpDispenser<DataApiBaseOp,
optionsBldr.vectorize(pf.apply(l), mf.apply(l), ak.apply(l), paramFunc.get().apply(l)) :
optionsBldr.vectorize(pf.apply(l), mf.apply(l), ak.apply(l));
} else {
// paramFunc ignored (due to signature of vectorize method)
optionsBldr = optionsBldr.vectorize(pf.apply(l), mf.apply(l));
if (paramFunc.isPresent()) {
optionsBldr = optionsBldr.vectorize(pf.apply(l), mf.apply(l), paramFunc.get().apply(l));
} else {
optionsBldr = optionsBldr.vectorize(pf.apply(l), mf.apply(l));
}
}
}
Optional<LongFunction<List>> allowFunc = op.getAsOptionalFunction("allowIndex", List.class);
@SuppressWarnings("unchecked")
Optional<LongFunction<List<String>>> allowFunc = (Optional<LongFunction<List<String>>>) (Optional<?>) op.getAsOptionalFunction("allowIndex", List.class);
if (allowFunc.isPresent()) {
LongFunction<List> af = allowFunc.get();
optionsBldr = optionsBldr.indexingAllow(Arrays.toString(af.apply(l).toArray(new String[0])));
LongFunction<List<String>> af = allowFunc.get();
optionsBldr = optionsBldr.indexingAllow(af.apply(l).toArray(new String[0]));
}
Optional<LongFunction<List>> denyFunc = op.getAsOptionalFunction("denyIndex", List.class);
@SuppressWarnings("unchecked")
Optional<LongFunction<List<String>>> denyFunc = (Optional<LongFunction<List<String>>>) (Optional<?>) op.getAsOptionalFunction("denyIndex", List.class);
if (denyFunc.isPresent()) {
LongFunction<List> df = denyFunc.get();
optionsBldr = optionsBldr.indexingDeny(Arrays.toString(df.apply(l).toArray(new String[0])));
LongFunction<List<String>> df = denyFunc.get();
optionsBldr = optionsBldr.indexingDeny(df.apply(l).toArray(new String[0]));
}
return optionsBldr;
@@ -22,12 +22,17 @@ import com.datastax.astra.client.collections.exceptions.TooManyDocumentsToCountE
import com.datastax.astra.client.collections.definition.documents.Document;
import com.datastax.astra.client.core.query.Filter;
import java.util.Optional;
public class DataApiCollectionCountDocumentsOp extends DataApiBaseOp {
private final Collection<Document> collection;
private final Filter filter;
private final int upperBound;
private final Optional<Integer> upperBound;
public DataApiCollectionCountDocumentsOp(Database db, Collection<Document> collection, Filter filter, int upperBound) {
private final int MAX_UPPER_BOUND = 1000;
private final int SILENT_FAILED_COUNT_RESULT = -1;
public DataApiCollectionCountDocumentsOp(Database db, Collection<Document> collection, Filter filter, Optional<Integer> upperBound) {
super(db);
this.collection = collection;
this.filter = filter;
@@ -36,10 +41,21 @@ public class DataApiCollectionCountDocumentsOp extends DataApiBaseOp {
@Override
public Object apply(long value) {
// upper-bound being optional enables a pattern that ignores the "moreData"
// (getting rid of the 'upper bound' client-only feature). Still honored if passed (incl. throwing the error).
int upperBoundToUse = MAX_UPPER_BOUND;
boolean shouldThrowBoundExceeded = false;
if (upperBound.isPresent()) {
upperBoundToUse = upperBound.get();
shouldThrowBoundExceeded = true;
}
try {
return collection.countDocuments(filter, upperBound);
return collection.countDocuments(filter, upperBoundToUse);
} catch (TooManyDocumentsToCountException e) {
throw new RuntimeException(e);
if (shouldThrowBoundExceeded) {
throw new RuntimeException(e);
}
return SILENT_FAILED_COUNT_RESULT;
}
}
}
@@ -0,0 +1,43 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.ops;
import com.datastax.astra.client.collections.Collection;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.collections.definition.documents.Document;
import com.datastax.astra.client.collections.commands.cursor.CollectionFindAndRerankCursor;
import com.datastax.astra.client.collections.commands.options.CollectionFindAndRerankOptions;
public class DataApiCollectionFindAndRerankOp extends DataApiBaseOp {
private final Collection<Document> collection;
private final Filter filter;
private final CollectionFindAndRerankOptions options;
public DataApiCollectionFindAndRerankOp(Database db, Collection<Document> collection, Filter filter, CollectionFindAndRerankOptions options) {
super(db);
this.collection = collection;
this.filter = filter;
this.options = options;
}
@Override
public Object apply(long value) {
CollectionFindAndRerankCursor<Document, Document> cursor = collection.findAndRerank(filter, options);
return cursor.toList();
}
}
@@ -21,21 +21,24 @@ import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.collections.definition.documents.Document;
import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.collections.commands.Update;
import com.datastax.astra.client.collections.commands.options.CollectionFindOneAndUpdateOptions;
public class DataApiCollectionFindOneAndUpdateOp extends DataApiBaseOp {
private final Collection<Document> collection;
private final Filter filter;
private final Update update;
private final CollectionFindOneAndUpdateOptions options;
public DataApiCollectionFindOneAndUpdateOp(Database db, Collection<Document> collection, Filter filter, Update update) {
public DataApiCollectionFindOneAndUpdateOp(Database db, Collection<Document> collection, Filter filter, Update update, CollectionFindOneAndUpdateOptions options) {
super(db);
this.collection = collection;
this.filter = filter;
this.update = update;
this.options = options;
}
@Override
public Object apply(long value) {
return collection.findOneAndUpdate(filter, update);
return collection.findOneAndUpdate(filter, update, options);
}
}
@@ -0,0 +1,45 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.ops;
import com.datastax.astra.client.collections.Collection;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.collections.exceptions.TooManyDocumentsToCountException;
import com.datastax.astra.client.collections.definition.documents.Document;
import com.datastax.astra.client.core.query.Filter;
public class DataApiCollectionLegacyCountDocumentsOp extends DataApiBaseOp {
private final Collection<Document> collection;
private final Filter filter;
private final int upperBound;
public DataApiCollectionLegacyCountDocumentsOp(Database db, Collection<Document> collection, Filter filter, int upperBound) {
super(db);
this.collection = collection;
this.filter = filter;
this.upperBound = upperBound;
}
@Override
public Object apply(long value) {
try {
return collection.countDocuments(filter, upperBound);
} catch (TooManyDocumentsToCountException e) {
throw new RuntimeException(e);
}
}
}
@@ -19,10 +19,10 @@ package io.nosqlbench.adapter.dataapi.ops;
import com.datastax.astra.client.collections.Collection;
import com.datastax.astra.client.databases.Database;
public class DataApiCollectionDeleteAllOp extends DataApiBaseOp {
public class DataApiCollectionLegacyDeleteAllOp extends DataApiBaseOp {
private final Collection collection;
public DataApiCollectionDeleteAllOp(Database db, Collection collection) {
public DataApiCollectionLegacyDeleteAllOp(Database db, Collection collection) {
super(db);
this.collection = collection;
}
@@ -19,11 +19,11 @@ package io.nosqlbench.adapter.dataapi.ops;
import com.datastax.astra.client.collections.Collection;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.collections.definition.documents.Document;
public class DataApiCollectionFindByIdOp extends DataApiBaseOp {
public class DataApiCollectionLegacyFindByIdOp extends DataApiBaseOp {
private final Collection<Document> collection;
private final Object id;
public DataApiCollectionFindByIdOp(Database db, Collection<Document> collection, Object id) {
public DataApiCollectionLegacyFindByIdOp(Database db, Collection<Document> collection, Object id) {
super(db);
this.collection = collection;
this.id = id;
@@ -19,14 +19,15 @@ package io.nosqlbench.adapter.dataapi.ops;
import com.datastax.astra.client.collections.Collection;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.core.query.Filters;
public class DataApiCollectionFindDistinctOp extends DataApiBaseOp {
public class DataApiCollectionLegacyFindDistinctOp extends DataApiBaseOp {
private final Collection collection;
private final String fieldName;
private final Filter filter;
private final Class<?> resultClass;
public DataApiCollectionFindDistinctOp(Database db, Collection collection, String fieldName, Filter filter, Class<?> resultClass) {
public DataApiCollectionLegacyFindDistinctOp(Database db, Collection collection, String fieldName, Filter filter, Class<?> resultClass) {
super(db);
this.collection = collection;
this.fieldName = fieldName;
@@ -0,0 +1,44 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.ops;
import com.datastax.astra.client.collections.Collection;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.collections.definition.documents.Document;
import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.collections.commands.Update;
import com.datastax.astra.client.collections.commands.options.CollectionFindOneAndUpdateOptions;
public class DataApiCollectionLegacyFindOneAndUpdateOp extends DataApiBaseOp {
private final Collection<Document> collection;
private final Filter filter;
private final Update update;
private final CollectionFindOneAndUpdateOptions options;
public DataApiCollectionLegacyFindOneAndUpdateOp(Database db, Collection<Document> collection, Filter filter, Update update, CollectionFindOneAndUpdateOptions options) {
super(db);
this.collection = collection;
this.filter = filter;
this.update = update;
this.options = options;
}
@Override
public Object apply(long value) {
return collection.findOneAndUpdate(filter, update, options);
}
}
@@ -24,12 +24,12 @@ import com.datastax.astra.client.collections.definition.documents.Document;
import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.core.query.Sort;
public class DataApiCollectionFindVectorFilterOp extends DataApiBaseOp {
public class DataApiCollectionLegacyFindVectorFilterOp extends DataApiBaseOp {
private final Collection<Document> collection;
private final Filter filter;
private final CollectionFindOptions options;
public DataApiCollectionFindVectorFilterOp(Database db, Collection<Document> collection, float[] vector, int limit, Filter filter) {
public DataApiCollectionLegacyFindVectorFilterOp(Database db, Collection<Document> collection, float[] vector, int limit, Filter filter) {
super(db);
this.collection = collection;
this.filter = filter;
@@ -23,11 +23,11 @@ import com.datastax.astra.client.core.query.Sort;
import com.datastax.astra.client.collections.commands.cursor.CollectionFindCursor;
import com.datastax.astra.client.collections.commands.options.CollectionFindOptions;
public class DataApiCollectionFindVectorOp extends DataApiBaseOp {
public class DataApiCollectionLegacyFindVectorOp extends DataApiBaseOp {
private final Collection<Document> collection;
private final CollectionFindOptions options;
public DataApiCollectionFindVectorOp(Database db, Collection<Document> collection, float[] vector, int limit) {
public DataApiCollectionLegacyFindVectorOp(Database db, Collection<Document> collection, float[] vector, int limit) {
super(db);
this.collection = collection;
this.options = new CollectionFindOptions().sort(Sort.vector(vector)).limit(limit);
@@ -21,11 +21,11 @@ import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.collections.definition.documents.Document;
import com.datastax.astra.client.collections.commands.results.CollectionInsertOneResult;
public class DataApiCollectionInsertOneVectorOp extends DataApiBaseOp {
public class DataApiCollectionLegacyInsertOneVectorOp extends DataApiBaseOp {
private final Document doc;
private final String collectionName;
public DataApiCollectionInsertOneVectorOp(Database db, String collectionName, Document doc, float[] vector) {
public DataApiCollectionLegacyInsertOneVectorOp(Database db, String collectionName, Document doc, float[] vector) {
super(db);
this.collectionName = collectionName;
this.doc = doc.vector(vector);
@@ -21,13 +21,13 @@ import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.core.query.Filter;
import com.datastax.astra.client.collections.commands.options.CollectionReplaceOneOptions;
public class DataApiCollectionReplaceOneOp extends DataApiBaseOp {
public class DataApiCollectionLegacyReplaceOneOp extends DataApiBaseOp {
private final Collection collection;
private final Filter filter;
private final Object replacement;
private final CollectionReplaceOneOptions options;
public DataApiCollectionReplaceOneOp(Database db, Collection collection, Filter filter, Object replacement, CollectionReplaceOneOptions options) {
public DataApiCollectionLegacyReplaceOneOp(Database db, Collection collection, Filter filter, Object replacement, CollectionReplaceOneOptions options) {
super(db);
this.collection = collection;
this.filter = filter;
@@ -0,0 +1,43 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.ops;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.collections.definition.documents.Document;
import com.datastax.astra.client.core.commands.Command;
import java.util.Map;
public class DataApiDbCreateCollectionOp extends DataApiBaseOp {
private final String collectionName;
private final Map<String, Object> definition;
public DataApiDbCreateCollectionOp(Database db, String collectionName, Map<String, Object> definition) {
super(db);
this.collectionName = collectionName;
this.definition = definition;
}
@Override
public Object apply(long value) {
Document ccPayload = new Document();
ccPayload.append("name", collectionName);
ccPayload.append("options", definition);
Command ccCommand = new Command("createCollection", ccPayload);
return db.runCommand(ccCommand);
}
}
@@ -18,9 +18,9 @@ package io.nosqlbench.adapter.dataapi.ops;
import com.datastax.astra.client.databases.Database;
public class DataApiDropCollectionOp extends DataApiBaseOp {
public class DataApiDbDeleteCollectionOp extends DataApiBaseOp {
private final String collectionName;
public DataApiDropCollectionOp(Database db, String collectionName) {
public DataApiDbDeleteCollectionOp(Database db, String collectionName) {
super(db);
this.collectionName = collectionName;
}
@@ -19,11 +19,11 @@ package io.nosqlbench.adapter.dataapi.ops;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.collections.definition.CollectionDefinition;
public class DataApiCreateCollectionOp extends DataApiBaseOp {
public class DataApiLegacyCreateCollectionOp extends DataApiBaseOp {
private final String collectionName;
private final CollectionDefinition definition;
public DataApiCreateCollectionOp(Database db, String collectionName, CollectionDefinition definition) {
public DataApiLegacyCreateCollectionOp(Database db, String collectionName, CollectionDefinition definition) {
super(db);
this.collectionName = collectionName;
this.definition = definition;
@@ -19,12 +19,12 @@ package io.nosqlbench.adapter.dataapi.ops;
import com.datastax.astra.client.databases.Database;
import com.datastax.astra.client.collections.definition.CollectionDefinition;
public class DataApiCreateCollectionWithClassOp extends DataApiBaseOp {
public class DataApiLegacyCreateCollectionWithClassOp extends DataApiBaseOp {
private final String collectionName;
private final CollectionDefinition definition;
private final Class<?> clazz;
public DataApiCreateCollectionWithClassOp(Database db, String collectionName, CollectionDefinition definition, Class<?> clazz) {
public DataApiLegacyCreateCollectionWithClassOp(Database db, String collectionName, CollectionDefinition definition, Class<?> clazz) {
super(db);
this.collectionName = collectionName;
this.definition = definition;
@@ -0,0 +1,33 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
package io.nosqlbench.adapter.dataapi.ops;
import com.datastax.astra.client.databases.Database;
public class DataApiLegacyDeleteCollectionOp extends DataApiBaseOp {
private final String collectionName;
public DataApiLegacyDeleteCollectionOp(Database db, String collectionName) {
super(db);
this.collectionName = collectionName;
}
@Override
public Object apply(long value) {
db.dropCollection(collectionName);
return null;
}
}
@@ -17,36 +17,69 @@
package io.nosqlbench.adapter.dataapi.ops;
public enum DataApiOpType {
create_collection,
insert_many,
insert_one,
insert_one_vector,
find,
find_one,
find_one_and_delete,
find_one_and_update,
find_vector,
find_vector_filter,
update_one,
update_many,
delete_one,
delete_many,
delete_collection,
list_collections,
list_collection_names,
estimated_document_count,
find_by_id,
find_distinct,
count_documents,
replace_one,
find_one_and_replace,
delete_all,
create_collection_with_class,
// TO-DO OPS
// admin ops:
create_database,
list_databases,
drop_database,
get_database_info,
// db-admin ops:
create_namespace,
list_namespaces,
drop_namespace,
// in-database ops:
list_collections,
list_collection_names,
// LEGACY OPS
// admin ops:
// db-admin ops:
// in-database ops:
create_collection,
create_collection_with_class,
delete_collection,
// in-collection ops:
insert_one,
insert_one_vector,
insert_many,
delete_one,
delete_many,
delete_all,
find_one_and_delete,
find,
find_vector,
find_vector_filter,
find_by_id,
find_distinct,
find_one,
update_one,
find_one_and_update,
replace_one,
find_one_and_replace,
update_many,
estimated_document_count,
count_documents,
// NEW-STYLE OPS
// admin ops:
// db-admin ops:
// in-database ops:
db_create_collection,
db_delete_collection,
// in-collection ops:
collection_insert_one,
collection_insert_many,
collection_delete_many,
collection_delete_one,
collection_find_one_and_delete,
collection_find,
collection_find_one,
collection_find_and_rerank,
collection_update_one,
collection_find_one_and_update,
collection_find_one_and_replace,
collection_update_many,
collection_estimated_document_count,
collection_count_documents,
}
@@ -0,0 +1,25 @@
/*
* Copyright (c) nosqlbench
*
* 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.
*/
/// This package is the top-level entry point for the NoSQLBench Data API adapter (`dataapi`).
/// It wires together the standard adapter architecture:
/// {@link io.nosqlbench.adapter.dataapi.DataApiDriverAdapter} (registered via `@Service`),
/// {@link io.nosqlbench.adapter.dataapi.DataApiOpMapper} (dispatches to per-op dispensers),
/// and {@link io.nosqlbench.adapter.dataapi.DataApiSpace} (holds the driver client state).
///
/// Op dispensers live in the `opdispensers` sub-package; their corresponding runnable ops
/// live in the `ops` sub-package.
package io.nosqlbench.adapter.dataapi;
@@ -1,254 +0,0 @@
min_version: "5.21.0"
description: |
A basic workload that uses the DataStax Data API Client in Java, emulating what
applications would do in the native stack.
variations:
without vector:
with _id:
search by id=
search by id<
NOT USED: with uuid:
with vector:
with _id:
search by id=
search by id<
vector search with filter by id<
vector search with vector ~
with uuid:
vector search with vector ~
cardinality=TEMPLATE(cardinality,1000)
collection=TEMPLATE(collection,keyvalue)
dimensions=TEMPLATE(dimensions,1536)
similarity=TEMPLATE(similarity,COSINE)
keycount=TEMPLATE(keycount,TEMPLATE(cardinality))
valuecount=TEMPLATE(valuecount,TEMPLATE(cardinality))
rampup-threads=TEMPLATE(rampup-threads,100)
scenarios:
astra_dapi_kv_id:
schema: >-
run driver=dataapi
tags==block:schema_kv
threads==1 cycles==UNDEF
rampup: >-
run driver=dataapi
tags==block:rampup_kv_id
cycles===TEMPLATE(rampup-cycles,TEMPLATE(cardinality))
threads=TEMPLATE(rampup-threads)
errors=count
find_kv_by_id: >-
run driver=dataapi
tags==block:find_kv_by_id
cycles===TEMPLATE(main-cycles,1000)
threads=auto errors=count
find_kv_lt_id: >-
run driver=dataapi
tags==block:find_kv_lt_id
cycles===TEMPLATE(main-cycles,1000)
threads=auto errors=count
astra_dapi_v1536_id:
schema_vector: >-
run driver=dataapi
tags==block:schema_v1536
threads==1 cycles==UNDEF
rampup_vector: >-
run driver=dataapi
tags==block:rampup_v1536_id
cycles===TEMPLATE(rampup-cycles,TEMPLATE(cardinality))
threads=TEMPLATE(rampup-threads)
errors=count
find_kv_by_id: >-
run driver=dataapi
tags==block:find_kv_by_id
cycles===TEMPLATE(main-cycles,1000)
threads=auto errors=count
find_kv_lt_id: >-
run driver=dataapi
tags==block:find_kv_lt_id
cycles===TEMPLATE(main-cycles,1000)
threads=auto errors=count
find_by_vector: >-
run driver=dataapi
tags==block:find_by_vector
cycles===TEMPLATE(main-cycles,TEMPLATE(cardinality))
threads=auto errors=count
find_by_vector_lt_id: >-
run driver=dataapi
tags==block:find_by_vector_lt_id
cycles===TEMPLATE(main-cycles,TEMPLATE(cardinality))
threads=auto errors=count
astra_dapi_v1536_uuid:
schema_vector: >-
run driver=dataapi
tags==block:schema_v1536
threads==1 cycles==UNDEF
rampup_vector: >-
run driver=dataapi
tags==block:rampup_v1536_uuid
cycles===TEMPLATE(rampup-cycles,TEMPLATE(cardinality))
threads=TEMPLATE(rampup-threads)
errors=count
find_by_vector: >-
run driver=dataapi
tags==block:find_by_vector
cycles===TEMPLATE(main-cycles,TEMPLATE(cardinality))
threads=auto errors=count
bindings:
seq_key: Mod(TEMPLATE(keycount)); ToString() -> String
seq_value: Hash(); Mod(TEMPLATE(valuecount)); ToString() -> String
rw_key: TEMPLATE(keydist,Uniform(0,TEMPLATE(keycount))); ToString() -> String
rw_key_num: TEMPLATE(keydist,Uniform(0,TEMPLATE(keycount)));
rw_value: Hash(); TEMPLATE(valdist,Uniform(0,TEMPLATE(valuecount))); ToString() -> String
vector_value: HashedFloatVectors(TEMPLATE(dimensions,1536));
request_id: ToHashedUUID(); ToString();
params:
cl: TEMPLATE(cl,LOCAL_QUORUM)
instrument: true
blocks:
reset_schema:
ops:
drop_index:
raw: |-
DROP INDEX IF EXISTS TEMPLATE(keyspace, baselines).TEMPLATE(table,keyvalue)_value_idx;
drop-table:
raw: |-
DROP TABLE IF EXISTS TEMPLATE(keyspace, baselines).TEMPLATE(table,keyvalue);
# Schema
schema_kv:
ops:
delete_collection_op:
delete_collection: "TEMPLATE(collection)"
create_collection_op:
create_collection: "TEMPLATE(collection)"
schema_v1536:
ops:
delete_collection_op_v:
delete_collection: "TEMPLATE(collection)_v"
create_collection_op_v:
create_collection: "TEMPLATE(collection)_v"
dimensions: TEMPLATE(dimensions)
similarity: TEMPLATE(similarity)
# Rampup
rampup_kv_id:
ops:
insert_one_op:
insert_one: "TEMPLATE(collection)"
document:
_id: "{seq_key}"
value: "{seq_value}"
# rampup_kv_uuid:
# ops:
# insert_one_op:
# insert_one: "TEMPLATE(collection)"
# document:
# value: "{seq_value}"
rampup_v1536_id:
ops:
insert_one_op_v:
insert_one_vector: "TEMPLATE(collection)_v"
document:
_id: "{seq_key}"
value: "{seq_value}"
vector: "{vector_value}"
rampup_v1536_uuid:
ops:
insert_one_op_v:
insert_one_vector: "TEMPLATE(collection)_v"
document:
value: "{seq_value}"
vector: "{vector_value}"
find_kv_by_id:
ops:
find_op:
find: "TEMPLATE(collection)"
filters:
- conjunction: "and"
operator: "eq"
field: "_id"
value: "{rw_key}"
find_kv_lt_id:
params:
ratio: 5
ops:
find_kv_id_lt:
find: "TEMPLATE(collection)"
filters:
- conjunction: "and"
operator: "lt"
field: "_id"
value: "{rw_key_num}"
find_by_vector_lt_id:
params:
ratio: 5
ops:
find_kv_id_lt:
find: "TEMPLATE(collection)"
filters:
- conjunction: "and"
operator: "lt"
field: "_id"
value: "{rw_key_num}"
vector: "{vector_value}"
find_by_vector:
params:
ratio: 5
ops:
find_op_filter_v:
find_vector_filter: "TEMPLATE(collection)"
vector: "{vector_value}"
# main_ann_with_vector_limit_20:
# params:
# ratio: 5
# ops:
# find_op:
# find: "TEMPLATE(collection)"
# sort:
# vector: "{vector_value}"
# options:
# limit: 20
# schema_with_text_sai:
# ops:
# delete_collection_op:
# delete_collection: "TEMPLATE(collection)"
# create_collection_op:
# create_collection: "TEMPLATE(collection)"
# rampup_with_text_sai:
# ops:
# insert_one_op:
# insert_one: "TEMPLATE(collection)"
# document:
# _id: "{seq_key}"
# value: "{seq_value}"
# main_read_with_text_sai:
# params:
# ratio: 5
# ops:
# find_op:
# find: "TEMPLATE(collection)"
# filter:
# value: "{rw_value}"
@@ -1,11 +0,0 @@
scenarios:
default:
create_collection: run driver=dataapi tags==blocks:create_collection cycles=1
blocks:
create_collection:
ops:
op1:
create_collection: "collectionName"
dimensions: 10
similarity: "COSINE"
@@ -0,0 +1,274 @@
# Run with e.g.:
#
# nb data_api_workload.yaml <SCENARIO_NAME> \
# astraApiEndpoint=$ASTRA_DB_API_ENDPOINT \
# astraToken=$ASTRA_DB_APPLICATION_TOKEN \
# namespace=$ASTRA_DB_KEYSPACE \
# [main-cycles=<e.g. 200>] \
# [rampup-insertmany-cycles=<e.g. 10, relevant if vector scenario which has an insert many>]
#
# where <SCENARIO_NAME> = data_api_scenario_base / data_api_scenario_vector
description: |
A simple workload that uses the Data API Client to perform
writes, reads and vector reads similar to a realistic general-purpose application.
One scenario does not involve vectors, the other does.
The vector scenario demonstrates bulk insert (which can be done regardless of vector or not).
data_api_scenario_base:
schema
rampup (single-document insertions)
find one by document _id
find one by another document field
find (many) with a inequality filter on a field
data_api_scenario_vector:
schema
rampup (single-document insertions)
rampup (fewer multi-document insert-many)
find one by document _id
find one by another document field
find (many) with a inequality filter on a field
vector ANN find
vector ANN find plus filter conditions on other fields
NOTE: 'rampup-threads' cannot exceed 'cardinality'
cardinality=TEMPLATE(cardinality,1000)
collection=TEMPLATE(collection,dataapi_collection)
dimension=TEMPLATE(dimension,1536)
similarity=TEMPLATE(similarity,cosine)
valuecount=TEMPLATE(valuecount,TEMPLATE(cardinality))
rampup-threads=TEMPLATE(rampup-threads,100)
rampup-insertmany-cycles=TEMPLATE(rampup-insertmany-cycles,5)
scenarios:
data_api_scenario_base:
schema: >-
run driver=dataapi
tags==block:schema_base
threads==1 cycles==UNDEF
rampup:
run driver=dataapi
tags==block:rampup_base
cycles===TEMPLATE(rampup-cycles,TEMPLATE(cardinality))
threads=TEMPLATE(rampup-threads)
errors=count
find_by_id:
run driver=dataapi
tags==block:find_by_id
cycles===TEMPLATE(main-cycles,1000)
threads=auto
errors=count
find_by_value:
run driver=dataapi
tags==block:find_by_value
cycles===TEMPLATE(main-cycles,1000)
threads=auto
errors=count
find_by_ineq:
run driver=dataapi
tags==block:find_by_ineq
cycles===TEMPLATE(main-cycles,1000)
threads=auto
errors=count
data_api_scenario_vector:
schema: >-
run driver=dataapi
tags==block:schema_vector
threads==1 cycles==UNDEF
rampup:
run driver=dataapi
tags==block:rampup_vector
cycles===TEMPLATE(rampup-cycles,TEMPLATE(cardinality))
threads=TEMPLATE(rampup-threads)
errors=count
rampup_insertmany:
run driver=dataapi
tags==block:rampup_vector_insertmany
cycles===TEMPLATE(rampup-insertmany-cycles,TEMPLATE(cardinality))
threads=TEMPLATE(rampup-threads)
errors=count
find_by_id:
run driver=dataapi
tags==block:find_by_id
cycles===TEMPLATE(main-cycles,1000)
threads=auto
errors=count
find_by_value:
run driver=dataapi
tags==block:find_by_value
cycles===TEMPLATE(main-cycles,1000)
threads=auto
errors=count
find_by_ineq:
run driver=dataapi
tags==block:find_by_ineq
cycles===TEMPLATE(main-cycles,1000)
threads=auto
errors=count
vector_find:
run driver=dataapi
tags==block:vector_find
cycles===TEMPLATE(main-cycles,1000)
threads=auto
errors=count
filtered_vector_find:
run driver=dataapi
tags==block:filtered_vector_find
cycles===TEMPLATE(main-cycles,1000)
threads=auto
errors=count
bindings:
my_seq: Mod(TEMPLATE(cardinality))
my_value: Hash(); ToString() -> String
my_id: Mod(TEMPLATE(cardinality)); ToString() -> String
my_vector: Add(100); HashedFloatVectors(TEMPLATE(dimension,1536));
# vectors for batches of "insert_many":
ins_vector_00: Add(200); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_01: Add(201); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_02: Add(202); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_03: Add(203); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_04: Add(204); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_05: Add(205); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_06: Add(206); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_07: Add(207); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_08: Add(208); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_09: Add(209); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_10: Add(210); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_11: Add(211); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_12: Add(212); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_13: Add(213); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_14: Add(214); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_15: Add(215); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_16: Add(216); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_17: Add(217); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_18: Add(218); HashedFloatVectors(TEMPLATE(dimension,1536));
ins_vector_19: Add(219); HashedFloatVectors(TEMPLATE(dimension,1536));
blocks:
schema_base:
ops:
create_collection_base_op:
db_create_collection: "TEMPLATE(collection)"
definition: {}
schema_vector:
ops:
create_collection_vector_op:
db_create_collection: "TEMPLATE(collection)"
definition:
vector:
dimension: TEMPLATE(dimension,1536)
metric: TEMPLATE(similarity,cosine)
rampup_base:
ops:
insert_one_base_op:
collection_insert_one: "TEMPLATE(collection)"
document:
_id: "{my_id}"
some_value: "{my_value}"
seq: "{my_seq}"
rampup_vector:
ops:
insert_one_vector_op:
collection_insert_one: "TEMPLATE(collection)"
document:
_id: "{my_id}"
some_value: "{my_value}"
seq: "{my_seq}"
$vector: "{my_vector}"
rampup_vector_insertmany:
ops:
insert_many_vector_op:
collection_insert_many: "TEMPLATE(collection)"
documents:
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_00}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_01}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_02}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_03}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_04}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_05}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_06}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_07}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_08}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_09}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_10}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_11}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_12}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_13}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_14}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_15}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_16}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_17}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_18}"}
- {"some_value":"{my_value}","seq":"{my_seq}","$vector":"{ins_vector_19}"}
find_by_id:
ops:
find_by_id_op:
collection_find_one: "TEMPLATE(collection)"
filter:
_id: "{my_id}"
projection:
include:
- "value"
- "seq"
find_by_value:
ops:
find_by_value_op:
collection_find_one: "TEMPLATE(collection)"
filter:
some_value: "{my_value}"
projection:
include:
- "*"
find_by_ineq:
ops:
find_by_ineq_op:
collection_find: "TEMPLATE(collection)"
filter:
seq:
$lt: "{my_seq}"
limit: 10
sort:
seq: desc
projection:
include:
- "seq"
vector_find:
ops:
vector_find_op:
collection_find: "TEMPLATE(collection)"
limit: 10
vector: "{my_vector}"
include_similarity: true
projection:
include:
- "seq"
filtered_vector_find:
ops:
vector_find_op:
collection_find: "TEMPLATE(collection)"
limit: 10
vector: "{my_vector}"
filter:
seq:
$lt: "{my_seq}"
some_value:
$exists: true
projection:
include:
- "seq"
exclude:
- "_id"
@@ -1,18 +0,0 @@
scenarios:
default:
delete_many: run driver=dataapi tags==blocks:delete_many cycles=1
blocks:
delete_many:
ops:
op1:
delete_many: "collectionName"
filters:
- conjunction: "and"
operator: "lt"
field: "field1"
value: 10
- conjunction: "or"
operator: "eq"
field: "field2"
value: "value2"
@@ -1,13 +0,0 @@
scenarios:
default:
delete_one: run driver=dataapi tags==blocks:delete_one cycles=1
blocks:
delete_one:
ops:
op1:
delete_one: "collectionName"
sort:
type: "asc"
field: "field1"
vector: "1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0"
@@ -1,9 +0,0 @@
scenarios:
default:
drop_collection: run driver=dataapi tags==blocks:drop_collection cycles=1
blocks:
drop_collection:
ops:
op1:
drop_collection: "collectionName"
@@ -1,9 +0,0 @@
scenarios:
default:
estimated_document_count: run driver=dataapi tags==blocks:estimated_document_count cycles=1
blocks:
estimated_document_count:
ops:
op1:
estimated_document_count: "collectionName"
@@ -0,0 +1,47 @@
scenarios:
default:
find_one: run driver=dataapi tags==blocks:find_one cycles=2
# Run with e.g.:
# nb example_workload.yaml \
# astraApiEndpoint=$ASTRA_DB_API_ENDPOINT \
# astraToken=$ASTRA_DB_APPLICATION_TOKEN \
# namespace=$ASTRA_DB_KEYSPACE
bindings:
query_vector: Add(37); HashedFloatVectors(TEMPLATE(dimensions,1024));
blocks:
find_one:
ops:
example_regular_find:
collection_find: "TEMPLATE(collection)"
filter:
$and:
- field:
$lt: 10
- block:
$eq: "A"
sort:
idx: asc
limit: 5
projection:
include:
- "idx"
- "block"
exclude:
- "_id"
example_vector_find:
collection_find: "TEMPLATE(collection)"
vector: "{query_vector}"
# alternatively:
# vector: "1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0..."
# vector: [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0...]
limit: 5
projection:
include:
- "idx"
- "block"
exclude:
- "_id"
@@ -0,0 +1,51 @@
scenarios:
default:
find_one: run driver=dataapi tags==blocks:find_one cycles=2
# Run with e.g.:
# nb example_workload_legacy.yaml \
# astraApiEndpoint=$ASTRA_DB_API_ENDPOINT \
# astraToken=$ASTRA_DB_APPLICATION_TOKEN \
# namespace=$ASTRA_DB_KEYSPACE
bindings:
query_vector: Add(37); HashedFloatVectors(TEMPLATE(dimensions,1024));
blocks:
find_one:
ops:
legacy_example_regular_find:
find: "TEMPLATE(collection)"
filters:
- conjunction: "and"
operator: "lt"
field: "field"
value: 10
- conjunction: "and"
operator: "eq"
field: "block"
value: "A"
sort:
type: "asc"
field: "idx"
limit: 5
projection:
include:
- "idx"
- "block"
exclude:
- "_id"
legacy_example_vector_find:
find: "TEMPLATE(collection)"
vector: "{query_vector}"
# alternatively:
# vector: "1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0..."
# vector: [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0...]
limit: 5
projection:
include:
- "idx"
- "block"
exclude:
- "_id"
@@ -1,26 +0,0 @@
scenarios:
default:
find: run driver=dataapi tags==blocks:find cycles=10
blocks:
find:
ops:
op1:
find: "collectionName"
filters:
- conjunction: "and"
operator: "lt"
field: "field1"
value: 10
- conjunction: "or"
operator: "eq"
field: "field2"
value: "value2"
sort:
type: "asc"
field: "field1"
vector: "1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0"
projection:
include:
- "field1"
- "field2"
@@ -1,26 +0,0 @@
scenarios:
default:
find_one: run driver=dataapi tags==blocks:find_one cycles=10
blocks:
find_one:
ops:
op1:
find_one: "collectionName"
filters:
- conjunction: "and"
operator: "lt"
field: "field1"
value: 10
- conjunction: "or"
operator: "eq"
field: "field2"
value: "value2"
sort:
type: "asc"
field: "field1"
vector: "1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0"
projection:
include:
- "field1"
- "field2"
@@ -1,25 +0,0 @@
scenarios:
default:
find_one_and_delete: run driver=dataapi tags==blocks:find_one_and_delete cycles=1
blocks:
find_one_and_delete:
ops:
op1:
find_one_and_delete: "collectionName"
filters:
- conjunction: "and"
operator: "lt"
field: "field1"
value: 10
- conjunction: "or"
operator: "eq"
field: "field2"
value: "value2"
sort:
type: "asc"
field: "field1"
projection:
include:
- "field1"
- "field2"
@@ -1,4 +0,0 @@
min_version: "5.21.0"
description: |
TBD, similar to find_one_and_delete.yaml
@@ -1,17 +0,0 @@
scenarios:
default:
insert_many: run driver=dataapi tags==blocks:insert_many cycles=1
blocks:
insert_many:
ops:
op1:
insert_many: "collectionName"
options:
chunkSize: "1000"
concurrency: "10"
ordered: "false"
documents:
- "{valid json here}"
- "{valid json here}"
- "{valid json here}"
@@ -1,10 +0,0 @@
scenarios:
default:
insert_one: run driver=dataapi tags==blocks:insert_one cycles=1
blocks:
insert_one:
ops:
op1:
insert_one: "collectionName"
document: "{valid json here}"
@@ -1,11 +0,0 @@
scenarios:
default:
insert_one: run driver=dataapi tags==blocks:insert_one cycles=1
blocks:
insert_one:
ops:
op1:
insert_one: "collectionName"
document: "{valid json here}"
vector: "1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0"
@@ -0,0 +1,407 @@
# NOTE: this file only lists the (legacy) operations and their syntax in a self-documenting comment-rich form.
# It is not a full NB workload file. Refer to the full examples for the overall format.
blocks:
my_block:
ops:
# LEGACY "deleteCollection", fully documented:
delcoll_legacy:
delete_collection: "TEMPLATE(collection)"
# LEGACY "createCollection", fully documented:
crcoll_legacy:
create_collection: "TEMPLATE(collection)"
### optional vector dimensionality (if present, it's a vector collection. Note plural, 'dimensions'):
# dimensions: 1024
#### optional similarity function for vector (case-insensitive "COSINE"/"EUCLIDEAN"/"DOT_PRODUCT"):
# similarity: DOT_PRODUCT
#### optional (required for vectorize) service provider:
# serviceProvider: voyageAI
#### optional (required for vectorize) service model (note a typo, 'mode'):
# serviceMode: voyage-2
#### optional KMS secret name for vectorize API key:
# serviceSharedSecretKey: SHARED_SECRET_EMBEDDING_API_KEY_VOYAGEAI
#### optional parameters map for vectorize service/model:
# serviceParameters:
# autoTruncate: true
#### optional default ID type (case-sensitive "objectId"/"uuidv6"/"uuidv7"/"uuid"):
# collectionType: objectId
#### optional, allow-list for indexing (error if denyIndex present as well):
# allowIndex:
# - aField1
# - aField2
#### optional, deny-list for indexing (error if allowIndex present as well):
# denyIndex:
# - aField1
# - aField2
# LEGACY "insertMany", fully documented:
im_legacy:
insert_many: "TEMPLATE(collection)"
# required documents to insert (a list of strings, each a serialized JSON):
documents:
- "{\"a\": 1}"
- "{\"a\": 2}"
- "{\"a\": 3}"
#### optional, options (each must be a string if provided):
# options:
# # how to split the input list into separate requests (default 50):
# chunkSize: "20"
# # concurrency level for running chunk insertions (must be 1 if ordered=true):
# concurrency: "5"
# # ordered insertion? true = insert sequentially and fail fast; false = no order guarantees, proceed even if errors:
# ordered: "false"
# # timeout for each individual chunk insertion (milliseconds):
# timeout: "5000"
# LEGACY "insertOne", fully documented (note: identical to new-style op except in the op name):
i1_legacy:
insert_one: "TEMPLATE(collection)"
#### required document to insert, free-form (_id can be omitted; note alternate forms for optional $vector):
document:
new: true
# $vector: [1,2,3,4,5,6,7,8,9,0]
# $vector:
# $binary: "P4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAA=="
# LEGACY "insertOne" with explicit vector, fully documented:
i1vec_legacy:
insert_one_vector: "TEMPLATE(collection)"
#### required document to insert, free-form (_id can be omitted, $vector is ignored):
document:
new: true
# required vector value to come with the document (three alternate forms):
vector: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
# vector: "1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0"
# vector:
# - 1.0
# - 1.0
# - 1.0
# - 1.0
# - 1.0
# - 1.0
# - 1.0
# - 1.0
# - 1.0
# - 1.0
# LEGACY "updateMany", fully documented:
um_legacy:
update_many: "TEMPLATE(collection)"
#### required update, free-form:
updates:
$set:
updated: "yes!"
#### optional filter (either all 'and' or all 'or'):
# filters:
# - conjunction: "and"
# operator: "eq"
# field: "old"
# value: true
#### optional upsert:
# upsert: true
# LEGACY replace_one, fully documented:
repl1_legacy:
replace_one: "TEMPLATE(collection)"
#### required replacement document in its entirety, free-form (_id can be omitted):
document:
new: true
#### optional filter (either all 'and' or all 'or'):
# filters:
# - conjunction: "and"
# operator: "eq"
# field: "old"
# value: true
#### optional sort (can only 1 sort, not if 'vector/ize'):
# sort:
# type: "asc"
# field: "idx"
#### optional vector (not if 'sort/vectorize'; float list/string repr with commas):
# vector: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
#### optional vectorize (not if 'sort/vector'):
# vectorize: "query string"
#### optional projection (either include or exclude, list of fields):
# projection:
# exclude:
# - "_id"
#### optional upsert:
# upsert: true
#### optional 'returnDocument' (values: 'after'/'before')
# returnDocument: after
# LEGACY "findOneAndReplace". Fully documented:
f1repl_legacy:
find_one_and_replace: "TEMPLATE(collection)"
#### required replacement document in its entirety, free-form (_id can be omitted):
document:
new: true
#### optional filter (either all 'and' or all 'or'):
# filters:
# - conjunction: "and"
# operator: "eq"
# field: "idx"
# value: 20
#### optional sort (can only 1 sort, not if 'vector/ize'):
# sort:
# type: "asc"
# field: "idx"
#### optional vector (not if 'sort/vectorize'; float list/string repr with commas):
# vector: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
#### optional vectorize (not if 'sort/vector'):
# vectorize: "query string"
#### optional projection (either include or exclude, list of fields):
# projection:
# exclude:
# - "idx"
#### optional upsert:
# upsert: true
#### optional 'returnDocument' (values: 'after'/'before')
# returnDocument: after
# LEGACY "findOneAndDelete". Fully documented:
f1del_legacy:
find_one_and_delete: "TEMPLATE(collection)"
#### optional filter (either all 'and' or all 'or'):
# filters:
# - conjunction: "and"
# operator: "eq"
# field: "idx"
# value: 20
#### optional sort (can only 1 sort, not if 'vector/ize'):
# sort:
# type: "asc"
# field: "idx"
#### optional vector (not if 'sort/vectorize'; float list/string repr with commas):
# vector: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
#### optional vectorize (not if 'sort/vector'):
# vectorize: "query string"
#### optional projection (either include or exclude, list of fields):
# projection:
# exclude:
# - "idx"
# LEGACY "updateOne". Fully documented:
u1_legacy:
update_one: "TEMPLATE(collection)"
#### required update (free-form):
update:
$set:
updated: true
#### optional filter (either all 'and' or all 'or'):
# filters:
# - conjunction: "and"
# operator: "eq"
# field: "idx"
# value: 29
#### optional upsert:
# upsert: true
#### optional sort (can only 1 sort, not if 'vector/ize'):
# sort:
# type: "asc"
# field: "idx"
#### optional vector (not if 'sort/vectorize'; float list/string repr with commas):
# vector: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
#### optional vectorize (not if 'sort/vector'):
# vectorize: "query string"
# LEGACY countDocuments. Fully documented:
cd_legacy:
count_documents: "TEMPLATE(collection)"
#### required upper bound (a client-side notion. Error thrown if result exceeds it):
upperbound: 100
#### optional filter (either all 'and' or all 'or'):
# filters:
# - conjunction: "and"
# operator: "lt"
# field: "idx"
# value: 100
# LEGACY estimatedDocumentCount (only the op name differs from 'new'). Fully documented:
edc_legacy:
estimated_document_count: "TEMPLATE(collection)"
# LEGACY delete-all, i.e. "deleteMany" with no filters (truncate). Fully documented:
da_legacy:
delete_all: "TEMPLATE(collection_to_truncate)"
# LEGACY "deleteMany". Fully documented:
dm_legacy:
delete_many: "TEMPLATE(collection)"
#### required filter (either all 'and' or all 'or', cannot be empty):
filters:
- conjunction: "and"
operator: "gt"
field: "idx"
value: 52
# LEGACY "deleteOne". Fully documented:
d1_legacy:
delete_one: "TEMPLATE(collection)"
#### required filter (either all 'and' or all 'or', cannot be empty):
filters:
- conjunction: "and"
operator: "lt"
field: "idx"
value: 100
#### optional sort (can only 1 sort, not if 'vector/ize'):
# sort:
# type: "asc"
# field: "idx"
#### optional vector (not if 'sort/vectorize'; float list/string repr with commas):
# vector: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
#### optional vectorize (not if 'sort/vector'):
# vectorize: "query string"
# LEGACY "find (no vectors)". Fully documented:
find_legacy:
find: "TEMPLATE(collection)"
#### optional filter (either all 'and' or all 'or'):
# filters:
# - conjunction: "and"
# operator: "lt"
# field: "idx"
# value: 80
#### optional limit:
# limit: 40
#### optional skip:
# skip: 1
#### optional includeSimilarity (default to true in this op):
# includeSimilarity: true
#### optional sort (can only 1 sort, not if 'vector/ize'):
# sort:
# type: "asc"
# field: "idx"
#### optional vector (not if 'sort/vectorize'; float list/string repr with commas):
# vector: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
#### optional vectorize (not if 'sort/vector'):
# vectorize: "query string"
#### optional projection (either include or exclude, list of fields):
# projection:
# include:
# - "idx"
#### optional pageState to start the find from:
# pageState: "LQAAAAEBAAAAJDc1NDgyNzk5LTQwN2ItNGEyOC04ODI3LTk5NDA3YmFhMjg4YQDwf///zQA="
# LEGACY "find with vector". Fully documented:
find_vector_legacy:
find_vector: "TEMPLATE(collection)"
#### required sort vector (float list/string repr with commas):
vector: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
#### optional, limit (defaults to 100):
# limit: 3
# LEGACY "find with vector and a filter". Fully documented:
find_vector_filter_legacy:
find_vector_filter: "TEMPLATE(collection)"
#### required sort vector (float list/string repr with commas):
vector: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
#### optional filter (either all 'and' or all 'or'):
# filters:
# - conjunction: "and"
# operator: "lt"
# field: "idx"
# value: 80
#### optional, limit (defaults to 100):
# limit: 3
# LEGACY "findOne (by ID)". Fully documented:
find_by_id_legacy:
find_by_id: "TEMPLATE(collection)"
#### required id of the target document:
id: "zzz"
# LEGACY "findOne". Fully documented:
f1_legacy:
find_one: "TEMPLATE(collection)"
#### optional filter (either all 'and' or all 'or'):
# filters:
# - conjunction: "and"
# operator: "eq"
# field: "field1"
# value: 74
#### optional sort (can only 1 sort, not if 'vector/ize'):
# sort:
# type: "asc"
# field: "idx"
#### optional vector (not if 'sort/vectorize'; float list/string repr with commas):
# vector: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
#### optional vectorize (not if 'sort/vector'):
# vectorize: "query string"
#### optional projection (either include or exclude, list of fields):
# projection:
# include:
# - "field1"
# - "field2"
#### optional includeSimilarity (default to true in this op):
# include_similarity: false
# LEGACY "findOneAndUpdate". Fully documented:
f1upd_legacy:
find_one_and_update: "TEMPLATE(collection)"
#### required update (can only 1 update op, legacy op limitation):
updates:
update:
operation: inc
field: "incd field"
value: 500
#### optional sort (can only 1 sort, not if 'vector/ize'):
# sort:
# type: "asc"
# field: "idx"
#### optional vector (not if 'sort/vectorize'; float list/string repr with commas):
# vector: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
#### optional vectorize (not if 'sort/vector'):
# vectorize: "query string"
#### optional filter (either all 'and' or all 'or'):
# filters:
# - conjunction: "and"
# operator: "eq"
# field: "field1"
# value: 74
#### optional upsert:
# upsert: true
# LEGACY find-distinct (client-side operation). Fully documented:
find_distinct_op_legacy:
find_distinct: "TEMPLATE(collection)"
#### required field to read:
fieldName: "the_field"
#### optional filter (either all 'and' or all 'or'):
# filters:
# - conjunction: "and"
# operator: "eq"
# field: "field1"
# value: 74
#### optional class for the result (default: java.lang.String)
# resultClass: "java.lang.Double"
# LEGACY create collection 'with class' (the 'with class' is a client-side operation only). Fully documented:
create_collection_with_class_legacy:
create_collection_with_class: "TEMPLATE(collection_to_create)"
#### required class name for the collection instance returned (default is shown):
createClass: "com.datastax.astra.client.collections.definition.documents.Document"
### optional vector dimensionality (if present, it's a vector collection. Note plural, 'dimensions'):
# dimensions: 1024
#### optional similarity function for vector (case-insensitive "COSINE"/"EUCLIDEAN"/"DOT_PRODUCT"):
# similarity: DOT_PRODUCT
#### optional (required for vectorize) service provider:
# serviceProvider: voyageAI
#### optional (required for vectorize) service model (note a typo, 'mode'):
# serviceMode: voyage-2
#### optional KMS secret name for vectorize API key:
# serviceSharedSecretKey: SHARED_SECRET_EMBEDDING_API_KEY_VOYAGEAI
#### optional parameters map for vectorize service/model:
# serviceParameters:
# autoTruncate: true
#### optional default ID type (case-sensitive "objectId"/"uuidv6"/"uuidv7"/"uuid"):
# collectionType: objectId
#### optional, allow-list for indexing (error if denyIndex present as well):
# allowIndex:
# - aField1
# - aField2
#### optional, deny-list for indexing (error if allowIndex present as well):
# denyIndex:
# - aField1
# - aField2
@@ -1,9 +0,0 @@
scenarios:
default:
list_collection_names: run driver=dataapi tags==blocks:list_collection_names cycles=1
blocks:
list_collection_names:
ops:
op1:
list_collection_names: TBD
@@ -1,9 +0,0 @@
scenarios:
default:
list_collections: run driver=dataapi tags==blocks:list_collections cycles=1
blocks:
list_collections:
ops:
op1:
list_collections: TBD
@@ -0,0 +1,341 @@
# NOTE: this file only lists the operations and their syntax in a self-documenting comment-rich form.
# It is not a full NB workload file. Refer to the full examples for the overall format.
blocks:
my_block:
ops:
# NEW "deleteCollection", fully documented:
delcoll:
db_delete_collection: "TEMPLATE(collection)"
# NEW "createCollection", fully documented:
crcoll:
db_create_collection: "TEMPLATE(collection)"
#### required collection definition (free-form, must be valid Data API syntax)
definition:
vector:
dimension: 1024
metric: "dot_product"
service:
provider: "voyageAI"
modelName: "voyage-2"
authentication:
providerKey: "SHARED_SECRET_EMBEDDING_API_KEY_VOYAGEAI"
parameters:
autoTruncate: true
indexing:
allow:
- aField1
- aField2
defaultId:
type: objectId
# NEW "insertMany", fully documented:
im:
collection_insert_many: "TEMPLATE(collection)"
# required documents to insert, list of free-form objects:
documents:
- {"a": 1}
- a: 2
b: my_string
c:
c1: subitem1
c2: 1999
- a: 3
$vector: [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
#### optional ordered flag, default=false (true = insert sequentially and fail fast; false = no order guarantees, proceed even if errors):
# ordered: false
#### optional for splitting the input list into separate requests (default 50):
#### NOTE: in a typical NoSQLBench workload, this should not count and not be used, meaning the amount of documents
#### submitted should be <= chunk size. This is because NB supposedly works in unit of requests to the server,
#### not mediated by manipulations from the Data API client.
# chunk_size: 20
# NEW "insertOne", fully documented:
i1:
collection_insert_one: "TEMPLATE(collection)"
#### required document to insert, free-form (_id can be omitted; note alternate forms for optional $vector):
document:
newv2: true
# $vector: [1,2,3,4,5,6,7,8,9,0]
# NEW "updateMany", fully documented:
um:
collection_update_many: "TEMPLATE(collection)"
#### (Note: may fail to update more than first page until fix to https://github.com/datastax/astra-db-java/issues/106 is released)
#### required update (free-form):
update:
$set:
updated: "yes!"
#### optional filter (free-form):
# filter:
# $and:
# - marker_field: present
# - not_a_field:
# $exists: false
#### optional upsert:
# upsert: true
# NEW "findOneAndReplace". Fully documented:
f1repl:
collection_find_one_and_replace: "TEMPLATE(collection)"
#### required replacement document in its entirety, free-form (_id can be omitted):
replacement:
new: true
#### optional filter (free-form):
# filter:
# $and:
# - _id:
# $ne: abcd0123
# - not_a_field:
# $exists: false
#### optional upsert:
# upsert: true
#### optional 'return_document' (values: 'after'/'before')
# return_document: after
#### optional sort (order matters; can't use if 'vector/ize'):
# sort:
# block: asc
# idx: desc
#### optional vector (not if 'sort/vectorize'; float list/string repr with commas):
# vector: [1,2,3,4,5,6,7,8,9,0]
#### optional vectorize (not if 'sort/vector'):
# vectorize: "query string"
#### optional projection (lists of fields; include and exclude can coexist only for special fields):
# projection:
# exclude:
# - "idx"
# NEW "findOneAndDelete". Fully documented:
f1del:
collection_find_one_and_delete: "TEMPLATE(collection)"
#### optional filter (free-form):
# filter:
# $and:
# - idx:
# $gte: 21
# - not_a_field:
# $exists: false
#### optional sort (order matters; can't use if 'vector/ize'):
# sort:
# block: asc
# idx: desc
#### optional vector (not if 'sort/vectorize'; float list/string repr with commas):
# vector: [1,2,3,4,5,6,7,8,9,0]
#### optional vectorize (not if 'sort/vector'):
# vectorize: "query string"
#### optional projection (lists of fields; include and exclude can coexist only for special fields):
# projection:
# exclude:
# - "idx"
# NEW "updateOne". Fully documented:
u1:
collection_update_one: "TEMPLATE(collection)"
#### required update (free-form):
update:
$set:
updated: true
#### optional filter (free-form):
# filter:
# $and:
# - idx: 29
# - not_a_field:
# $exists: false
#### optional upsert:
# upsert: true
#### optional sort (order matters; can't use if 'vector/ize'):
# sort:
# block: asc
# idx: desc
#### optional vector (not if 'sort/vectorize'; float list/string repr with commas):
# vector: [1,2,3,4,5,6,7,8,9,0]
#### optional vectorize (not if 'sort/vector'):
# vectorize: "query string"
# NEW "countDocuments". Fully documented:
cd:
collection_count_documents: "TEMPLATE(collection)"
#### optional filter (free-form):
# filter:
# fake_field:
# $exists: false
#### optional upper bound (a client-side notion. *If provided*, error thrown when exceeded)
# upper_bound: 100
# NEW "estimatedDocumentCount". Fully documented:
edc:
collection_estimated_document_count: "TEMPLATE(collection)"
# NEW "deleteMany". Fully documented:
dm:
collection_delete_many: "TEMPLATE(collection)"
#### required filter (free-form. truncate with 'filter: {}')
filter:
idx:
$gt: 40
# NEW "deleteOne". Fully documented:
d1:
collection_delete_one: "TEMPLATE(collection)"
#### required filter (free-form):
filter:
$and:
- idx:
$gte: 45
- the_field:
$exists: false
#### optional sort (order matters; can't use if 'vector/ize'):
# sort:
# block: asc
# idx: desc
#### optional vector (not if 'sort/vectorize'; float list/string repr with commas):
# vector: [1,2,3,4,5,6,7,8,9,0]
#### optional vectorize (not if 'sort/vector'):
# vectorize: "query string"
# NEW "find". Fully documented:
f:
collection_find: "TEMPLATE(collection)"
#### optional filter (free-form):
# filter:
# $or:
# - idx:
# $lt: 99
# - idx:
# $exists: false
#### optional sort (order matters; can't use if 'vector/ize'):
# sort:
# block: asc
# idx: desc
#### optional vector (not if 'sort/vectorize'; float list/string repr with commas):
# vector: [1,2,3,4,5,6,7,8,9,0]
#### optional vectorize (not if 'sort/vector'):
# vectorize: "query string"
#### optional limit:
# limit: 36
#### optional skip (only with non-vector sorting):
# skip: 45
#### optional projection (lists of fields; include and exclude can coexist only for special fields):
# projection:
# include:
# - "idx"
# - "bloppo"
#### optional includeSimilarity (default true for nb):
# include_similarity: false
#### optional includeSortVector (default false):
# include_sort_vector: true
# NEW "findOne". Fully documented:
f1:
collection_find_one: "TEMPLATE(collection)"
#### optional filter (free-form):
# filter:
# $and:
# - field1: "value1"
# - field2:
# $eq: 123
#### optional sort (order matters; can't use if 'vector/ize'):
# sort:
# block: asc
# idx: desc
#### optional vector (not if 'sort/vectorize'; float list/string repr with commas):
# vector: [1,2,3,4,5,6,7,8,9,0]
#### optional vectorize (not if 'sort/vector'):
# vectorize: "query string"
#### optional projection (lists of fields; include and exclude can coexist only for special fields):
# projection:
# include:
# - "field1"
# - "field2"
#### optional includeSimilarity:
# include_similarity: false
# NEW "findOneAndUpdate". Fully documented:
f1upd:
collection_find_one_and_update: "TEMPLATE(collection)"
#### required update (free-form):
update:
$set:
myfield2: "new_val"
$inc:
myfield: 200
myfield1: 20
#### optional sort (order matters; can't use if 'vector/ize'):
# sort:
# block: asc
# idx: desc
#### optional vector (not if 'sort/vectorize'; float list/string repr with commas):
# vector: [1,2,3,4,5,6,7,8,9,0]
#### optional vectorize (not if 'sort/vector'):
# vectorize: "query string"
#### optional filter (free-form):
# filter:
# $and:
# - field1: "value1"
# - field2:
# $eq: 123
#### optional upsert:
# upsert: true
# NEW "findAndRerank", fully documented:
farr:
collection_find_and_rerank: "TEMPLATE(collection)"
#### required sort clause. Must have '$hybrid' key, with one of the various forms accepted (also depending on collection settings):
sort:
$hybrid: bla
## alternative (explicit per-leg) sort form:
# sort:
# $hybrid:
# $vectorize: bli
# $lexical: blo
## alternative (explicit per-leg) sort form:
# sort:
# $hybrid:
# $vector: [0.1,0.2,0.3]
# $lexical: "bla"
## alternative (no-lexical) sort form:
# sort:
# $hybrid:
# $vectorize: bli
## alternative (no-lexical) sort form:
# sort:
# $hybrid:
# $vector: [0.1,0.2,0.3]
#### optional filter (free-form):
# filter:
# $vectorize:
# $exists: true
#### optional projection (lists of fields; include and exclude can coexist only for special fields):
# projection:
# include:
# - $vectorize
# exclude:
# - _id
#### optional limit:
# limit: 1
#### optional hybridLimits (can have either form):
# hybrid_limits: 10
## alternative (explicit per-leg) hybridLimits form:
# hybrid_limits:
# $vector: 11
# $lexical: 9
#### optional rerankOn:
# rerank_on: "$lexical"
#### optional rerankQuery:
# rerank_query: "ble"
#### optional includeScores (default false):
# include_scores: true
#### optional includeSortVector (default false):
# include_sort_vector: true
#### optional rerank override for this one call:
#### (Note: may not have effects until fix to https://github.com/datastax/astra-db-java/issues/109 released)
# rerank:
# provider: theProvider"
# modelName: "theModelName"
# authentication:
# providerKey: "bla"
# parameters:
# param1: value1
# param2: 999
@@ -1,6 +1,82 @@
---
source: nb-adapters/adapter-dataapi/src/main/resources/dataapi.md
---
# Data API
## DataStax Data API Adapter
# Data API adapter
This is a NB adapter for the [Data API](https://github.com/stargate/data-api), an HTTP API that can run on top of Cassandra and DataStax Astra DB.
The adapter is built on top of the [Java client](https://github.com/datastax/astra-db-java) for the Data API and exposes the same primitives as the Data API, in a 1:1 relation between ops and Data API commands wherever possible and exposing all of the command options when it makes sense to do so.
## Command-line parameters
_Note: this release of the adapter is designed to connect to **DataStax Astra DB's Data API** specifically. All examples refer to this case. Subsequent releases will expand the scope to non-Astra-DB instances of Data API._
Connection to the Data API requires an **API Endpoint** and an **Application Token**, plus specification of a **keyspace** to operate in. These are required parameters when launching a NB workload targeting the Data API:
```
astraToken="..."
astraApiEndpoint="https://..."
namespace="the_keyspace"
```
These values are used by the adapter to establish a `DataAPIClient`, from which all subsequent operations are spawned.
## Legacy vs. "new-style" operation
In September 2026, a major rework of the ops has been initiated, essentially marking all operations existing so far as "legacy" and introducing a whole new set of ops, coming with more extensible naming conventions (e.g. the legacy `find` op has become `collection_find`). The overhaul has reached its first milestone (collection CRUD and all collection operations).
The legacy operations received bug fixes (plus obvious additive extensions to their behaviour when it made sense to). So, no pre-existing workload will break. However, the user is encouraged to build new workload exclusively using the new-style operations.
For a detailed catalog of the legacy and the new-style operations, with their syntax, consult the "Examples" section below.
### Current status of the overhaul
**Done:**
- all collection DML ops;
- create/delete collection DDL;
- All known bugs in legacy operations are fixed.
**Coming next:**
- introduction of Table support;
- Administrative functions (create keyspace and so on), currently left as they were before the overhaul;
- Ability to target non-Astra and non-prod environments in full;
- Ability to supply special Data API-related secrets (such as embedding provider API keys for $vectorize operations).
## Usage notes (new-style ops)
Most commands support a free-form syntax for some of their parameters, such as the collection definition for `db_create_collection` or the insertee document in `collection_insert_one`. This is to give the most flexibility and future-proofing the op in case new syntax is added by the Data API.
In other cases, when it was deemed more convenient, the syntax is more constrained. All specifications are given in the supporting example op YAMLs under `activities/`.
### Vectors
Many commands allow to supply **vectors**: these can be expressed in the YAML:
- literally, as lists of (floating-point) numbers: `[0.1,-3.2,1.9]`;
- literally, as a string containing comma-separated floating points: `"0.1,-3.2,1.9"`;
- via an appropriate binding, e.g. `"{the_vector_binding}"`.
In any case, whenever the API Client is equipped to do so, vectors are transmitted in the bandwidth-optimized binary-encoded form regardless of how they are given. One _should not_ manually construct the binary-encoding syntax (e.g. as part of an insertee document for a `collection_insert_one` op).
## Client vs. 'raw Data API payloads'
An important virtue of the Java Data API client is that it handles headers, authentication, encoding/decoding of payloads and responses - with minimal overhead.
On the other hand, the client builds higher-level convenience features on top of the raw HTTP requests underlying the API: so, for example, what for the client is a single 200-item `insertMany(...)` invocation translates to a certain number of "chunked" Data API requests, each one inserting some of the items and executed with a degree of (client-managed) concurrency that depends on various settings. _This is a kind of sophistication that a typical usage of NB would not want_.
For this reason, the adapter strives to avoid patterns that would trigger such "too complex" behaviours: for instance, the client concurrency for multiple insertions is always hardcoded to one, leaving management of concurrent requests purely on the NB side.
It is, however, an ultimate responsibility of the Data API-savvy NB user to ensure full compliance with this tenet, for example never packing more than a pageful of items into a `collection_insert_many` operation's `documents` property.
## Examples
Consult the self-documenting YAML examples here:
- a simple [minimal running workload](activities/example_workload.yaml);
- (a simple [legacy minimal running workload](activities/example_workload_legacy.yaml));
- a realistic, [ready-to-run workload](activities/data_api_workload.yaml) demonstrating several ops
- [new-style ops full reference](activities/ops_reference.yaml);
- ([legacy ops full reference](activities/legacy_ops_reference.yaml)).