이터레이터 사용
Milvus는 대량의 엔티티로 결과를 반복하기 위한 검색 및 쿼리 반복기를 제공합니다. Milvus는 TopK를 16384로 제한하므로 사용자는 반복기를 사용하여 일괄 모드에서 컬렉션의 많은 수 또는 전체 엔티티를 반환할 수 있습니다.
개요
반복기는 기본 키 값과 부울 표현식을 사용하여 컬렉션 내의 대량의 데이터 또는 모든 데이터를 반복할 수 있는 강력한 도구입니다. 이를 통해 데이터를 검색하는 방식을 크게 개선할 수 있습니다. 시간이 지나면서 효율성이 떨어질 수 있는 기존의 오프셋 및 제한 매개변수 사용과 달리, 반복기는 보다 확장 가능한 솔루션을 제공합니다.
반복기 사용의 이점
단순성: 복잡한 오프셋 및 제한 설정이 필요 없습니다.
효율성: 필요한 데이터만 가져와서 확장 가능한 데이터 검색을 제공합니다.
일관성: 부울 필터로 일관된 데이터 세트 크기를 보장합니다.
참고
- 이 기능은 Milvus 2.3.x 이상에서 사용할 수 있습니다.
준비 단계
다음 단계에서는 Milvus에 연결하고, 컬렉션을 빠르게 설정하고, 무작위로 생성된 10,000개 이상의 엔티티를 컬렉션에 삽입하기 위해 코드의 용도를 변경합니다.
1단계: 컬렉션 만들기
를 사용하여 MilvusClient
을 사용하여 Milvus 서버에 연결하고 create_collection()
를 사용하여 컬렉션을 만듭니다.
사용 MilvusClientV2
을 사용하여 Milvus 서버에 연결하고 createCollection()
를 사용하여 컬렉션을 만듭니다.
from pymilvus import MilvusClient
# 1. Set up a Milvus client
client = MilvusClient(
uri="http://localhost:19530"
)
# 2. Create a collection
client.create_collection(
collection_name="quick_setup",
dimension=5,
)
import io.milvus.client.MilvusServiceClient;
import io.milvus.param.ConnectParam;
import io.milvus.param.highlevel.collection.CreateSimpleCollectionParam;
String CLUSTER_ENDPOINT = "http://localhost:19530";
// 1. Connect to Milvus server
ConnectParam connectParam = ConnectParam.newBuilder()
.withUri(CLUSTER_ENDPOINT)
.build();
MilvusServiceClient client = new MilvusServiceClient(connectParam);
// 2. Create a collection
CreateSimpleCollectionParam createCollectionParam = CreateSimpleCollectionParam.newBuilder()
.withCollectionName("quick_setup")
.withDimension(5)
.build();
client.createCollection(createCollectionParam);
2단계: 무작위로 생성된 엔티티 삽입하기
를 사용하여 insert()
를 사용하여 컬렉션에 엔티티를 삽입합니다.
사용 insert()
를 사용하여 컬렉션에 엔티티를 삽입합니다.
# 3. Insert randomly generated vectors
colors = ["green", "blue", "yellow", "red", "black", "white", "purple", "pink", "orange", "brown", "grey"]
data = []
for i in range(10000):
current_color = random.choice(colors)
current_tag = random.randint(1000, 9999)
data.append({
"id": i,
"vector": [ random.uniform(-1, 1) for _ in range(5) ],
"color": current_color,
"tag": current_tag,
"color_tag": f"{current_color}_{str(current_tag)}"
})
print(data[0])
# Output
#
# {
# "id": 0,
# "vector": [
# -0.5705990742218152,
# 0.39844925120642083,
# -0.8791287928610869,
# 0.024163154953680932,
# 0.6837669917169638
# ],
# "color": "purple",
# "tag": 7774,
# "color_tag": "purple_7774"
# }
res = client.insert(
collection_name="quick_setup",
data=data,
)
print(res)
# Output
#
# {
# "insert_count": 10000,
# "ids": [
# 0,
# 1,
# 2,
# 3,
# 4,
# 5,
# 6,
# 7,
# 8,
# 9,
# "(9990 more items hidden)"
# ]
# }
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import com.alibaba.fastjson.JSONObject;
import io.milvus.param.R;
import io.milvus.param.dml.InsertParam;
import io.milvus.response.MutationResultWrapper;
import io.milvus.grpc.MutationResult;
// 3. Insert randomly generated vectors into the collection
List<String> colors = Arrays.asList("green", "blue", "yellow", "red", "black", "white", "purple", "pink", "orange", "brown", "grey");
List<JSONObject> data = new ArrayList<>();
for (int i=0; i<10000; i++) {
Random rand = new Random();
String current_color = colors.get(rand.nextInt(colors.size()-1));
JSONObject row = new JSONObject();
row.put("id", Long.valueOf(i));
row.put("vector", Arrays.asList(rand.nextFloat(), rand.nextFloat(), rand.nextFloat(), rand.nextFloat(), rand.nextFloat()));
row.put("color_tag", current_color + "_" + String.valueOf(rand.nextInt(8999) + 1000));
data.add(row);
}
InsertParam insertParam = InsertParam.newBuilder()
.withCollectionName("quick_setup")
.withRows(data)
.build();
R<MutationResult> insertRes = client.insert(insertParam);
if (insertRes.getStatus() != R.Status.Success.getCode()) {
System.err.println(insertRes.getMessage());
}
MutationResultWrapper wrapper = new MutationResultWrapper(insertRes.getData());
System.out.println(wrapper.getInsertCount());
반복기를 사용한 검색
반복기를 사용하면 유사도 검색을 더욱 확장할 수 있습니다.
반복기를 사용하여 검색하려면 search_iterator() 메서드를 호출합니다:
이터레이터로 검색하려면 searchIterator() 메서드를 호출합니다:
검색 이터레이터를 초기화하여 검색 매개변수와 출력 필드를 정의합니다.
루프 내에서 next() 메서드를 사용하여 검색 결과를 페이지 매김합니다.
메서드가 빈 배열을 반환하면 루프가 종료되고 더 이상 페이지를 사용할 수 없습니다.
모든 결과에는 지정된 출력 필드가 포함됩니다.
모든 데이터가 검색되면 close() 메서드를 수동으로 호출하여 반복기를 닫습니다.
from pymilvus import Collection
# 4. Search with iterator
connections.connect(host="127.0.0.1", port=19530)
collection = Collection("quick_setup")
query_vectors = [[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]]
search_params = {
"metric_type": "IP",
"params": {"nprobe": 10}
}
iterator = collection.search_iterator(
data=query_vectors,
anns_field="vector",
batch_size=10,
param=search_params,
output_fields=["color_tag"],
limit=3
)
results = []
while True:
result = iterator.next()
if not result:
iterator.close()
break
results.extend(result)
for hit in result:
results.append(hit.to_dict())
print(results)
# Output
#
# [
# {
# "id": 1756,
# "distance": 2.0642056465148926,
# "entity": {
# "color_tag": "black_9109"
# }
# },
# {
# "id": 6488,
# "distance": 1.9437453746795654,
# "entity": {
# "color_tag": "purple_8164"
# }
# },
# {
# "id": 3338,
# "distance": 1.9107104539871216,
# "entity": {
# "color_tag": "brown_8121"
# }
# }
# ]
import io.milvus.param.dml.QueryIteratorParam;
import io.milvus.param.dml.SearchIteratorParam;
import io.milvus.response.QueryResultsWrapper;
import io.milvus.orm.iterator.SearchIterator;
// 4. Search with iterators
SearchIteratorParam iteratorParam = SearchIteratorParam.newBuilder()
.withCollectionName("quick_setup")
.withVectorFieldName("vector")
// Use withFloatVectors() in clusters compatible with Milvus 2.4.x
.withVectors(Arrays.asList(0.3580376395471989f, -0.6023495712049978f, 0.18414012509913835f, -0.26286205330961354f, 0.9029438446296592f))
.withBatchSize(10L)
.withParams("{\"metric_type\": \"COSINE\", \"params\": {\"level\": 1}}")
.build();
R<SearchIterator> searchIteratorRes = client.searchIterator(iteratorParam);
if (searchIteratorRes.getStatus() != R.Status.Success.getCode()) {
System.err.println(searchIteratorRes.getMessage());
}
SearchIterator searchIterator = searchIteratorRes.getData();
List<QueryResultsWrapper.RowRecord> results = new ArrayList<>();
while (true) {
List<QueryResultsWrapper.RowRecord> batchResults = searchIterator.next();
if (batchResults.isEmpty()) {
searchIterator.close();
break;
}
for (QueryResultsWrapper.RowRecord rowRecord : batchResults) {
results.add(rowRecord);
}
}
System.out.println(results.size());
파라미터 | 설명 |
---|---|
data |
벡터 임베딩의 목록. Milvus는 지정된 임베딩과 가장 유사한 벡터 임베딩을 검색합니다. |
anns_field |
현재 컬렉션에 있는 벡터 필드의 이름입니다. |
batch_size |
현재 반복기에서 next() 을 호출할 때마다 반환할 엔티티의 수.기본값은 1000입니다. 적절한 값으로 설정하여 반복당 반환할 엔티티 수를 제어합니다. |
param |
이 작업과 관련된 매개변수 설정
|
output_fields |
반환 시 각 엔티티에 포함할 필드 이름 목록. 기본값은 None입니다. 지정하지 않으면 기본 필드만 포함됩니다. |
limit |
반환할 총 엔티티 수. 기본값은 -1로, 일치하는 모든 엔티티가 반환됨을 나타냅니다. |
매개변수 | 설명 |
---|---|
withCollectionName |
컬렉션 이름을 설정합니다. 컬렉션 이름은 비어 있거나 null일 수 없습니다. |
withVectorFieldName |
대상 벡터 필드를 이름으로 설정합니다. 필드 이름은 비어 있거나 null일 수 없습니다. |
withVectors |
대상 벡터를 설정합니다. 최대 16384개의 벡터가 허용됩니다. |
withBatchSize |
현재 반복자에서 next() 을 호출할 때마다 반환할 엔티티 수입니다.기본값은 1000입니다. 적절한 값으로 설정하여 반복당 반환할 엔티티 수를 제어하세요. |
withParams |
검색 매개변수를 JSON 형식으로 지정합니다. 자세한 내용은 searchIterator()를 참조하세요. |
반복기를 사용한 쿼리
이터레이터로 쿼리하려면 query_iterator() 메서드를 호출합니다:
이터레이터로 쿼리하려면 쿼리이터레이터() 메서드를 호출합니다:
# 6. Query with iterator
iterator = collection.query_iterator(
batch_size=10, # Controls the size of the return each time you call next()
expr="color_tag like \"brown_8\"",
output_fields=["color_tag"]
)
results = []
while True:
result = iterator.next()
if not result:
iterator.close()
break
results.extend(result)
# 8. Check the search results
print(len(results))
print(results[:3])
# Output
#
# [
# {
# "color_tag": "brown_8785",
# "id": 94
# },
# {
# "color_tag": "brown_8568",
# "id": 176
# },
# {
# "color_tag": "brown_8721",
# "id": 289
# }
# ]
import io.milvus.param.dml.QueryIteratorParam;
import io.milvus.orm.iterator.QueryIterator;
// 5. Query with iterators
try {
Files.write(Path.of("results.json"), JSON.toJSONString(new ArrayList<>()).getBytes(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
QueryIteratorParam queryIteratorParam = QueryIteratorParam.newBuilder()
.withCollectionName("quick_setup")
.withExpr("color_tag like \"brown_8%\"")
.withBatchSize(50L)
.addOutField("vector")
.addOutField("color_tag")
.build();
R<QueryIterator> queryIteratRes = client.queryIterator(queryIteratorParam);
if (queryIteratRes.getStatus() != R.Status.Success.getCode()) {
System.err.println(queryIteratRes.getMessage());
}
QueryIterator queryIterator = queryIteratRes.getData();
while (true) {
List<QueryResultsWrapper.RowRecord> batchResults = queryIterator.next();
if (batchResults.isEmpty()) {
queryIterator.close();
break;
}
String jsonString = "";
List<JSONObject> jsonObject = new ArrayList<>();
try {
jsonString = Files.readString(Path.of("results.json"));
jsonObject = JSON.parseArray(jsonString).toJavaList(null);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (QueryResultsWrapper.RowRecord queryResult : batchResults) {
JSONObject row = new JSONObject();
row.put("id", queryResult.get("id"));
row.put("vector", queryResult.get("vector"));
row.put("color_tag", queryResult.get("color_tag"));
jsonObject.add(row);
}
try {
Files.write(Path.of("results.json"), JSON.toJSONString(jsonObject).getBytes(), StandardOpenOption.WRITE);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
파라미터 | 설명 |
---|---|
batch_size |
현재 반복자에서 next() 을 호출할 때마다 반환할 엔티티 수입니다.기본값은 1000입니다. 적절한 값으로 설정하여 반복당 반환할 엔티티 수를 제어할 수 있습니다. |
expr |
일치하는 엔티티를 필터링하기 위한 스칼라 필터링 조건. 기본값은 없음으로, 스칼라 필터링이 무시됨을 나타냅니다. 스칼라 필터링 조건을 작성하려면 부울 표현식 규칙을 참조하세요. |
output_fields |
반환 시 각 엔티티에 포함할 필드 이름 목록. 기본값은 None입니다. 지정하지 않으면 기본 필드만 포함됩니다. |
limit |
반환할 총 엔티티 수. 기본값은 -1로, 일치하는 모든 엔티티가 반환됨을 나타냅니다. |
매개변수 | 설명 |
---|---|
withCollectionName |
컬렉션 이름을 설정합니다. 컬렉션 이름은 비어 있거나 null일 수 없습니다. |
withExpr |
엔티티를 쿼리할 표현식을 설정합니다. 스칼라 필터링 조건을 작성하려면 부울 표현식 규칙을 참조하세요. |
withBatchSize |
현재 반복자에서 next() 을 호출할 때마다 반환할 엔티티 수.기본값은 1000입니다. 적절한 값으로 설정하여 반복당 반환할 엔티티 수를 제어합니다. |
addOutField |
출력 스칼라 필드를 지정합니다(선택 사항). |