Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
209 changes: 209 additions & 0 deletions examples/src/main/java/io/milvus/v2/TimestampExample.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
package io.milvus.v2;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import io.milvus.v1.CommonUtils;
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.ConsistencyLevel;
import io.milvus.v2.common.DataType;
import io.milvus.v2.common.IndexParam;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
import io.milvus.v2.service.collection.request.DropCollectionReq;
import io.milvus.v2.service.vector.request.*;
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.request.ranker.RRFRanker;
import io.milvus.v2.service.vector.response.QueryResp;
import io.milvus.v2.service.vector.response.SearchResp;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class TimestampExample {
private static final MilvusClientV2 client;

static {
ConnectConfig config = ConnectConfig.builder()
.uri("http://localhost:19530")
.build();
client = new MilvusClientV2(config);
}

private static final String COLLECTION_NAME = "java_sdk_example_timestamp_v2";
private static final String ID_FIELD = "ID";

private static final String FLOAT_VECTOR_FIELD = "vector";
private static final Integer FLOAT_VECTOR_DIM = 128;
private static final IndexParam.MetricType FLOAT_VECTOR_METRIC = IndexParam.MetricType.COSINE;

private static final String TIMESTAMP_VECTOR_FIELD = "tsz";


private static void createCollection() {
client.dropCollection(DropCollectionReq.builder()
.collectionName(COLLECTION_NAME)
.build());

// Create collection
CreateCollectionReq.CollectionSchema collectionSchema = CreateCollectionReq.CollectionSchema.builder()
.build();
collectionSchema.addField(AddFieldReq.builder()
.fieldName(ID_FIELD)
.dataType(DataType.Int64)
.isPrimaryKey(Boolean.TRUE)
.build());
collectionSchema.addField(AddFieldReq.builder()
.fieldName(FLOAT_VECTOR_FIELD)
.dataType(DataType.FloatVector)
.dimension(FLOAT_VECTOR_DIM)
.build());
collectionSchema.addField(AddFieldReq.builder()
.fieldName(TIMESTAMP_VECTOR_FIELD)
.dataType(DataType.Timestamptz)
.build());

List<IndexParam> indexes = new ArrayList<>();
indexes.add(IndexParam.builder()
.fieldName(FLOAT_VECTOR_FIELD)
.indexType(IndexParam.IndexType.AUTOINDEX)
.metricType(FLOAT_VECTOR_METRIC)
.build());
indexes.add(IndexParam.builder()
.fieldName(TIMESTAMP_VECTOR_FIELD)
.indexType(IndexParam.IndexType.STL_SORT)
.build());

CreateCollectionReq requestCreate = CreateCollectionReq.builder()
.collectionName(COLLECTION_NAME)
.collectionSchema(collectionSchema)
.indexParams(indexes)
.consistencyLevel(ConsistencyLevel.BOUNDED)
.build();
client.createCollection(requestCreate);
System.out.println("Collection created");
}

private static void insertData() {
int rowCount = 10;
ZoneId zone = ZoneId.of("Asia/Shanghai");
DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
System.out.printf("\n================= Insert with timezone: %s =================", zone);

// Insert entities by rows
List<JsonObject> rows = new ArrayList<>();
Gson gson = new Gson();
for (long i = 0L; i < rowCount; ++i) {
JsonObject row = new JsonObject();
row.addProperty(ID_FIELD, i);
row.add(FLOAT_VECTOR_FIELD, gson.toJsonTree(CommonUtils.generateFloatVector(FLOAT_VECTOR_DIM)));

LocalDateTime tt = LocalDateTime.of(2025, 1, 1, 0, 0, 0);
tt = tt.plusDays(i);
ZonedDateTime zt = tt.atZone(zone);
String tzFormat = zt.format(formatter);
System.out.println(tzFormat);
row.addProperty(TIMESTAMP_VECTOR_FIELD, tzFormat);
rows.add(row);
}

client.insert(InsertReq.builder()
.collectionName(COLLECTION_NAME)
.data(rows)
.build());
printRowCount();
}

private static void printRowCount() {
// Get row count, set ConsistencyLevel.STRONG to sync the data to query node so that data is visible
QueryResp countR = client.query(QueryReq.builder()
.collectionName(COLLECTION_NAME)
.outputFields(Collections.singletonList("count(*)"))
.consistencyLevel(ConsistencyLevel.STRONG)
.build());
System.out.printf("\n%d rows persisted", (long) countR.getQueryResults().get(0).getEntity().get("count(*)"));
}

private static void query(String timezone) {
QueryResp queryRet = client.query(QueryReq.builder()
.collectionName(COLLECTION_NAME)
.filter(ID_FIELD + " <= 3")
.timezone(timezone)
.outputFields(Collections.singletonList(TIMESTAMP_VECTOR_FIELD))
.build());
System.out.println("\nQuery results:");
List<QueryResp.QueryResult> records = queryRet.getQueryResults();
for (QueryResp.QueryResult record : records) {
System.out.println(record.getEntity());
}
}

private static void search(String timezone) {
SearchResp searchR = client.search(SearchReq.builder()
.collectionName(COLLECTION_NAME)
.data(Collections.singletonList(new FloatVec(CommonUtils.generateFloatVector(FLOAT_VECTOR_DIM))))
.limit(10)
.filter(ID_FIELD + " <= 3")
.timezone(timezone)
.outputFields(Collections.singletonList(TIMESTAMP_VECTOR_FIELD))
.build());
List<List<SearchResp.SearchResult>> searchResults = searchR.getSearchResults();
System.out.println("\nSearch results:");
for (List<SearchResp.SearchResult> results : searchResults) {
for (SearchResp.SearchResult result : results) {
System.out.printf("ID: %d, Score: %f, %s\n", (long) result.getId(), result.getScore(), result.getEntity().toString());
}
}
}

private static void hybridSearch(String timezone) {
// this is a single-route hybrid search, just demo the timezone paramter
List<AnnSearchReq> searchRequests = new ArrayList<>();
searchRequests.add(AnnSearchReq.builder()
.vectorFieldName(FLOAT_VECTOR_FIELD)
.vectors(Collections.singletonList(new FloatVec(CommonUtils.generateFloatVector(FLOAT_VECTOR_DIM))))
.limit(10)
.filter(ID_FIELD + " <= 3")
.timezone(timezone)
.build());

HybridSearchReq hybridSearchReq = HybridSearchReq.builder()
.collectionName(COLLECTION_NAME)
.searchRequests(searchRequests)
.functionScore(FunctionScore.builder()
.addFunction(RRFRanker.builder().k(10).build())
.build())
.limit(10)
.outFields(Collections.singletonList(TIMESTAMP_VECTOR_FIELD))
.build();
SearchResp searchResp = client.hybridSearch(hybridSearchReq);
List<List<SearchResp.SearchResult>> searchResults = searchResp.getSearchResults();
System.out.println("\nHybridSearch result:");
List<SearchResp.SearchResult> results = searchResults.get(0);
for (SearchResp.SearchResult result : results) {
System.out.println(result);
}
}

public static void main(String[] args) {
createCollection();
insertData();

List<String> timezones = Arrays.asList("America/Havana", "Africa/Bangui", "Australia/Sydney");

for (String timezone : timezones) {
System.out.printf("\n================= Query with timezone: %s =================", timezone);
query(timezone);
search(timezone);
hybridSearch(timezone);
}

client.close();
}
}
1 change: 1 addition & 0 deletions sdk-core/src/main/java/io/milvus/param/Constant.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class Constant {
public static final String ARRAY_MAX_CAPACITY = "max_capacity";
public static final String TOP_K = "topk";
public static final String IGNORE_GROWING = "ignore_growing";
public static final String TIMEZONE = "timezone";
public static final String REDUCE_STOP_FOR_BEST = "reduce_stop_for_best";
public static final String ITERATOR_FIELD = "iterator";
public static final String GROUP_BY_FIELD = "group_by_field";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public class AnnSearchReq {
private List<BaseVector> vectors;
private String params;
private IndexParam.MetricType metricType;
private String timezone;

private AnnSearchReq(AnnSearchReqBuilder builder) {
this.vectorFieldName = builder.vectorFieldName;
Expand All @@ -45,6 +46,7 @@ private AnnSearchReq(AnnSearchReqBuilder builder) {
this.vectors = builder.vectors;
this.params = builder.params;
this.metricType = builder.metricType;
this.timezone = builder.timezone;
}

public static AnnSearchReqBuilder builder() {
Expand Down Expand Up @@ -123,6 +125,10 @@ public void setMetricType(IndexParam.MetricType metricType) {
this.metricType = metricType;
}

public String getTimezone() {
return timezone;
}

@Override
public String toString() {
return "AnnSearchReq{" +
Expand All @@ -134,6 +140,7 @@ public String toString() {
", vectors=" + vectors +
", params='" + params + '\'' +
", metricType=" + metricType +
", timezone='" + timezone + '\'' +
'}';
}

Expand All @@ -146,6 +153,7 @@ public static class AnnSearchReqBuilder {
private List<BaseVector> vectors;
private String params;
private IndexParam.MetricType metricType = null;
private String timezone = "";

public AnnSearchReqBuilder vectorFieldName(String vectorFieldName) {
this.vectorFieldName = vectorFieldName;
Expand Down Expand Up @@ -195,6 +203,11 @@ public AnnSearchReqBuilder metricType(IndexParam.MetricType metricType) {
return this;
}

public AnnSearchReqBuilder timezone(String timezone) {
this.timezone = timezone;
return this;
}

public AnnSearchReq build() {
return new AnnSearchReq(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class QueryReq {
private long offset;
private long limit;
private boolean ignoreGrowing;
private String timezone;

// Extra parameters for query, timezone, time_fields, etc.
// Make sure the value can be converted to String by String.valueOf().
Expand Down Expand Up @@ -63,6 +64,7 @@ private QueryReq(QueryReqBuilder builder) {
this.ignoreGrowing = builder.ignoreGrowing;
this.queryParams = builder.queryParams;
this.filterTemplateValues = builder.filterTemplateValues;
this.timezone = builder.timezone;
}

public static QueryReqBuilder builder() {
Expand Down Expand Up @@ -149,6 +151,10 @@ public void setIgnoreGrowing(boolean ignoreGrowing) {
this.ignoreGrowing = ignoreGrowing;
}

public String getTimezone() {
return timezone;
}

public Map<String, Object> getQueryParams() {
return queryParams;
}
Expand Down Expand Up @@ -178,6 +184,7 @@ public String toString() {
", offset=" + offset +
", limit=" + limit +
", ignoreGrowing=" + ignoreGrowing +
", timezone='" + timezone + '\'' +
", queryParams=" + queryParams +
", filterTemplateValues=" + filterTemplateValues +
'}';
Expand All @@ -194,6 +201,7 @@ public static class QueryReqBuilder {
private long offset;
private long limit;
private boolean ignoreGrowing;
private String timezone = "";
private Map<String, Object> queryParams = new HashMap<>();
private Map<String, Object> filterTemplateValues = new HashMap<>();

Expand Down Expand Up @@ -247,6 +255,11 @@ public QueryReqBuilder ignoreGrowing(boolean ignoreGrowing) {
return this;
}

public QueryReqBuilder timezone(String timezone) {
this.timezone = timezone;
return this;
}

public QueryReqBuilder queryParams(Map<String, Object> queryParams) {
this.queryParams = queryParams;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public class SearchReq {
private Long gracefulTime; // deprecated
private ConsistencyLevel consistencyLevel;
private boolean ignoreGrowing;
private String timezone;
private String groupByFieldName;
private Integer groupSize;
private Boolean strictGroupSize;
Expand Down Expand Up @@ -92,6 +93,7 @@ private SearchReq(SearchReqBuilder builder) {
this.ranker = builder.ranker;
this.functionScore = builder.functionScore;
this.filterTemplateValues = builder.filterTemplateValues;
this.timezone = builder.timezone;
}

// Getters and Setters
Expand Down Expand Up @@ -235,6 +237,10 @@ public void setIgnoreGrowing(boolean ignoreGrowing) {
this.ignoreGrowing = ignoreGrowing;
}

public String getTimezone() {
return timezone;
}

public String getGroupByFieldName() {
return groupByFieldName;
}
Expand Down Expand Up @@ -303,6 +309,7 @@ public String toString() {
", gracefulTime=" + gracefulTime +
", consistencyLevel=" + consistencyLevel +
", ignoreGrowing=" + ignoreGrowing +
", timezone='" + timezone + '\'' +
", groupByFieldName='" + groupByFieldName + '\'' +
", groupSize=" + groupSize +
", strictGroupSize=" + strictGroupSize +
Expand Down Expand Up @@ -334,6 +341,7 @@ public static class SearchReqBuilder {
private Long gracefulTime = 5000L; // default value, deprecated
private ConsistencyLevel consistencyLevel = null; // default value
private boolean ignoreGrowing;
private String timezone = "";
private String groupByFieldName;
private Integer groupSize;
private Boolean strictGroupSize;
Expand Down Expand Up @@ -433,6 +441,11 @@ public SearchReqBuilder ignoreGrowing(boolean ignoreGrowing) {
return this;
}

public SearchReqBuilder timezone(String timezone) {
this.timezone = timezone;
return this;
}

public SearchReqBuilder groupByFieldName(String groupByFieldName) {
this.groupByFieldName = groupByFieldName;
return this;
Expand Down
Loading
Loading