Skip to content

Commit 3702c08

Browse files
yhmolikun
authored andcommitted
Fix a bug of QueryIterator that offset cannot exceed 16384 (milvus-io#1579)
Signed-off-by: yhmo <yihua.mo@zilliz.com>
1 parent f551c60 commit 3702c08

2 files changed

Lines changed: 37 additions & 18 deletions

File tree

sdk-core/src/main/java/io/milvus/orm/iterator/QueryIterator.java

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@
3333
import org.slf4j.Logger;
3434
import org.slf4j.LoggerFactory;
3535

36+
import java.util.ArrayList;
3637
import java.util.List;
3738

3839
import static io.milvus.param.Constant.NO_CACHE_ID;
40+
import static io.milvus.param.Constant.MAX_BATCH_SIZE;
3941
import static io.milvus.param.Constant.UNLIMITED;
4042

4143
public class QueryIterator {
@@ -96,7 +98,7 @@ public QueryIterator(QueryIteratorReq queryIteratorReq,
9698
// perform a query to get the first time stamp check point
9799
// the time stamp will be input for the next query to skip something
98100
private void setupTsByRequest() {
99-
QueryResults response = executeQuery(expr, 0L, 1L, 0L);
101+
QueryResults response = executeQuery(expr, 0L, 1L, 0L, true);
100102
if (response.getSessionTs() <= 0) {
101103
logger.warn("Failed to get mvccTs from milvus server, use client-side ts instead");
102104
// fall back to latest session ts by local time
@@ -114,11 +116,19 @@ private void seek() {
114116
return;
115117
}
116118

117-
QueryResults response = executeQuery(expr, 0L, offset, this.sessionTs);
118-
QueryResultsWrapper queryWrapper = new QueryResultsWrapper(response);
119-
List<QueryResultsWrapper.RowRecord> res = queryWrapper.getRowRecords();
120-
int resultIndex = Math.min(res.size(), (int) offset);
121-
updateCursor(res.subList(0, resultIndex));
119+
long currentOffset = offset;
120+
while (currentOffset > 0) {
121+
long limit = Math.min(MAX_BATCH_SIZE, currentOffset);
122+
String currentExpr = setupNextExpr();
123+
QueryResults response = executeQuery(currentExpr, 0L, limit, this.sessionTs, true);
124+
QueryResultsWrapper queryWrapper = new QueryResultsWrapper(response);
125+
List<QueryResultsWrapper.RowRecord> res = queryWrapper.getRowRecords();
126+
if (res.isEmpty()) {
127+
break;
128+
}
129+
updateCursor(res);
130+
currentOffset -= res.size();
131+
}
122132
offset = 0;
123133
}
124134

@@ -133,7 +143,7 @@ public List<QueryResultsWrapper.RowRecord> next() {
133143
iteratorCache.releaseCache(cacheIdInUse);
134144
String currentExpr = setupNextExpr();
135145
logger.debug("Query iterator next expression: " + currentExpr);
136-
QueryResults response = executeQuery(currentExpr, offset, batchSize, this.sessionTs);
146+
QueryResults response = executeQuery(currentExpr, offset, batchSize, this.sessionTs, false);
137147
QueryResultsWrapper queryWrapper = new QueryResultsWrapper(response);
138148
List<QueryResultsWrapper.RowRecord> res = queryWrapper.getRowRecords();
139149
maybeCache(res);
@@ -197,13 +207,18 @@ private boolean isResSufficient(List<QueryResultsWrapper.RowRecord> ret) {
197207
return ret != null && ret.size() >= batchSize;
198208
}
199209

200-
private QueryResults executeQuery(String expr, long offset, long limit, long ts) {
210+
private QueryResults executeQuery(String expr, long offset, long limit, long ts, boolean isSeek) {
211+
// for seeking offset, no need to return output fields
212+
List<String> outputFields = new ArrayList<>();
213+
if (!isSeek) {
214+
outputFields = queryIteratorParam.getOutFields();
215+
}
201216
QueryParam queryParam = QueryParam.newBuilder()
202217
.withDatabaseName(queryIteratorParam.getDatabaseName())
203218
.withCollectionName(queryIteratorParam.getCollectionName())
204219
.withConsistencyLevel(queryIteratorParam.getConsistencyLevel())
205220
.withPartitionNames(queryIteratorParam.getPartitionNames())
206-
.withOutFields(queryIteratorParam.getOutFields())
221+
.withOutFields(outputFields)
207222
.withExpr(expr)
208223
.withOffset(offset)
209224
.withLimit(limit)

sdk-core/src/test/java/io/milvus/v2/client/MilvusClientV2DockerTest.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,7 +1768,7 @@ public void testIterator() {
17681768
client.createCollection(requestCreate);
17691769

17701770
// insert rows
1771-
long count = 10000;
1771+
long count = 20000;
17721772
List<JsonObject> data = generateRandomData(collectionSchema, count);
17731773
InsertResp insertResp = client.insert(InsertReq.builder()
17741774
.collectionName(randomCollectionName)
@@ -1854,13 +1854,15 @@ public void testIterator() {
18541854
Assertions.assertTrue(counter > 0);
18551855

18561856
// query iterator
1857+
long from = 17777;
1858+
long to = 18000;
18571859
QueryIterator queryIterator = client.queryIterator(QueryIteratorReq.builder()
18581860
.collectionName(randomCollectionName)
1859-
.expr("int64_field < 300")
1861+
.expr("int64_field < " + String.valueOf(to))
18601862
.outputFields(Lists.newArrayList("*"))
18611863
.batchSize(50L)
1862-
.offset(5)
1863-
.limit(400)
1864+
.offset(from)
1865+
.limit(4000)
18641866
.consistencyLevel(ConsistencyLevel.EVENTUALLY)
18651867
.build());
18661868

@@ -1874,6 +1876,7 @@ public void testIterator() {
18741876
}
18751877

18761878
for (QueryResultsWrapper.RowRecord record : res) {
1879+
Assertions.assertInstanceOf(Long.class, record.get("id"));
18771880
Assertions.assertInstanceOf(Boolean.class, record.get("bool_field"));
18781881
Assertions.assertInstanceOf(Integer.class, record.get("int8_field"));
18791882
Assertions.assertInstanceOf(Integer.class, record.get("int16_field"));
@@ -1889,8 +1892,9 @@ public void testIterator() {
18891892
Assertions.assertInstanceOf(ByteBuffer.class, record.get("bfloat16_vector"));
18901893
Assertions.assertInstanceOf(SortedMap.class, record.get("sparse_vector"));
18911894

1892-
long int64Val = (long)record.get("int64_field");
1893-
Assertions.assertTrue(int64Val < 300L);
1895+
long int64Val = (long)record.get("id");
1896+
Assertions.assertTrue(int64Val >= from);
1897+
Assertions.assertTrue(int64Val < to);
18941898

18951899
String varcharVal = (String)record.get("varchar_field");
18961900
Assertions.assertTrue(varcharVal.startsWith("varchar_"));
@@ -1911,12 +1915,12 @@ public void testIterator() {
19111915
Assertions.assertEquals(DIMENSION*2, bfloat16Vector.limit());
19121916

19131917
SortedMap<Long, Float> sparseVector = (SortedMap<Long, Float>)record.get("sparse_vector");
1914-
Assertions.assertTrue(sparseVector.size() >= 10 && sparseVector.size() <= 20); // defined in generateSparseVector()
1918+
Assertions.assertTrue(sparseVector.size() >= 10 && sparseVector.size() < 20); // defined in generateSparseVector()
19151919

19161920
counter++;
19171921
}
19181922
}
1919-
Assertions.assertEquals(295, counter);
1923+
Assertions.assertEquals(to - from, counter);
19201924

19211925
// search iterator V2
19221926
SearchIteratorV2 searchIteratorV2 = client.searchIteratorV2(SearchIteratorReqV2.builder()
@@ -1976,7 +1980,7 @@ public void testIterator() {
19761980
Assertions.assertEquals(DIMENSION*2, bfloat16Vector.limit());
19771981

19781982
SortedMap<Long, Float> sparseVector = (SortedMap<Long, Float>)entity.get("sparse_vector");
1979-
Assertions.assertTrue(sparseVector.size() >= 10 && sparseVector.size() <= 20); // defined in generateSparseVector()
1983+
Assertions.assertTrue(sparseVector.size() >= 10 && sparseVector.size() < 20); // defined in generateSparseVector()
19801984

19811985
counter++;
19821986
}

0 commit comments

Comments
 (0)