テキストフィールド
AI 検索アプリケーションでは、ベクトル検索によって意味的に類似したエンティティを見つけることができますが、アプリケーションは多くの場合、各一致結果の背後にある元のソーステキストも必要とします。LLM またはエージェントは、そのテキストをコンテキストとして使用し、内容の読み取り、引用、要約、またはプロンプトへの結果の埋め込みを行うことができます。
Zilliz Cloud は、長いソーステキストをエンティティと直接保存するための TEXT スカラーフィールドタイプを提供します。一般的な値には、パッセージ、長いドキュメント、記事本文、チケット、ログなどがあります。固定の max_length を必要とする VARCHAR とは異なり、TEXT ではコレクションスキーマに最大バイト長を設定する必要はありません。
コレクションスキーマで TEXT フィールドを定義するには、datatype を DataType.TEXT に設定します。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- CSharp
- cURL
- Zilliz CLI
schema = MilvusClient.create_schema(auto_id=False, enable_dynamic_field=False)
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
schema.add_field(
field_name="content",
datatype=DataType.TEXT,
)
CreateCollectionReq.CollectionSchema schema = CreateCollectionReq.CollectionSchema.builder().build();
schema.addField(AddFieldReq.builder()
.fieldName("id")
.dataType(DataType.Int64)
.isPrimaryKey(true)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("content")
.dataType(DataType.Text)
.enableAnalyzer(true)
.build());
schema := entity.NewSchema().WithDynamicFieldEnabled(false).
WithField(entity.NewField().WithName("id").WithDataType(entity.FieldTypeInt64).WithIsPrimaryKey(true)).
WithField(entity.NewField().
WithName("content").
WithDataType(entity.FieldTypeText).
WithEnableAnalyzer(true))
let mut schema = CollectionSchema::new();
schema = schema.add_field(
FieldSchema::new()
.name("content")
.data_type(DataType::Text)
.enable_analyzer(true),
);
milvus::FieldSchema content_field("content", milvus::DataType::TEXT);
content_field.EnableAnalyzer(true);
const schema = [
{ name: "id", data_type: DataType.Int64, is_primary_key: true },
{ name: "content", data_type: DataType.Text, enable_analyzer: true },
];
var schema = new CollectionSchema
{
Name = "text_bm25_collection",
EnableDynamicFields = false
};
// DataType.Text is an alias of VarChar with analyzer support for full-text search
schema.Fields.Add(FieldSchema.CreateVarchar("content", maxLength: 65535, enableAnalyzer: true, enableMatch: true));
export contentField='{
"fieldName": "content",
"dataType": "Text",
"elementTypeParams": {
"enable_analyzer": true
}
}'
# Zilliz CLI
フィールドを定義した後、各エンティティにはそのフィールドに文字列値を含めることができます。値は他のスカラーフィールドと同様に挿入し、output_fields にフィールドを指定することでクエリまたは検索結果から返すことができます。
TEXT フィールドは null 値をサポートします。この機能を有効にするには、nullable を True に設定します。詳細については、Nullable Fields を参照してください。
制限事項
-
TEXTフィールドはプライマリフィールドにできません。プライマリフィールドはINT64とVARCHARをサポートします。 -
TEXTフィールドはPHRASE_MATCHをサポートしません。 -
TEXTフィールドはデフォルト値をサポートしません。 -
TEXTフィールドはスカラーインデックスをサポートしません。 -
TEXTは通常のメタデータフィルタリングを目的としたものではありません。短い文字列メタデータでフィルタリングする必要があり、フィールド値がVARCHARの長さ制限内に収まる場合は、VARCHARを使用してください。 -
TEXTフィールドは外部コレクションではサポートされていません。
TEXT または VARCHAR を選択する
TEXT と VARCHAR はどちらも文字列値を保存しますが、サポートするアプリケーションのニーズが異なります。エンティティの識別、分類、フィルタリングに使用する短く範囲の限られたメタデータには VARCHAR を使用します。LLM またはエージェントが読み取り、引用、要約、またはプロンプトの構築を行うための十分なコンテキストを得られる、より長いソースコンテンツには TEXT を使用します。
| 観点 | VARCHAR | TEXT |
|---|---|---|
| 最適な用途 | エンティティの識別、分類、またはフィルタリングに使用する短いメタデータ(title、tag、category、external_id など)。 | LLM またはエージェントのワークフローで使用するより長いソースコンテンツ(content、passage、article_body、log_message など)。 |
| 長さの設定 | フィールドが保存できる最大バイト数を定義する max_length が必要です。最大値は 65,535 バイトです。値がこの制限を超える可能性がある場合は、TEXT を使用してください。 | max_length が不要なため、スキーマでテキスト値に固定のバイト制限を設定する必要はありません。 |
| ストレージの動作 | フィールドに設定された max_length の範囲内で各値を保存します。 | より大きなテキスト値には自動ストレージ選択を使用します。 |
| プライマリフィールドのサポート | プライマリフィールドとして使用できます。 | プライマリフィールドとして使用できません。 |
| フィルタリング | category == "news" や tag in ["ai", "database"] など、フィルタ式に含める必要がある短い文字列メタデータに使用します。 | 通常のメタデータフィルタリングを目的としたものではありません。 |
VARCHAR フィールドの詳細については、VARCHAR Field を参照してください。
TEXT の一般的な用途は、BM25 を使用した全文検索です。このパターンでは、TEXT フィールドに元のソースコンテンツを保存し、BM25 がテキストを分析して、キーワードベースの一致をランキングするためのスパースベクトルを生成します。検索結果は、LLM またはエージェントのワークフローのコンテキストとして、一致した TEXT 値を返すことができます。次の例は、TEXT フィールドを BM25 の入力フィールドとして使用する方法を示しています。全文検索の概念とクエリオプションについては、Full Text Search を参照してください。
ステップ 1: TEXT フィールドを含むコレクションを作成する
次の例では、ソースコンテンツ用の TEXT フィールドと、BM25 で生成されたスパースベクトル用のスパースベクトルフィールドを含むコレクションを作成します。BM25 関数は、content からトークン化されたテキストを、sparse に保存されるスパースベクトルに変換します。
BM25 全文検索では、入力 TEXT フィールドに enable_analyzer=True を設定する必要があります。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- CSharp
- cURL
- Zilliz CLI
from pymilvus import MilvusClient, DataType
from pymilvus import DataType, Function, FunctionType, MilvusClient
client = MilvusClient(uri="YOUR_CLUSTER_ENDPOINT")
COLLECTION_NAME = "text_bm25_collection"
if client.has_collection(COLLECTION_NAME):
client.drop_collection(COLLECTION_NAME)
schema = client.create_schema(auto_id=False, enable_dynamic_field=False)
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
schema.add_field(
field_name="content",
datatype=DataType.TEXT,
enable_analyzer=True,
)
schema.add_field(field_name="sparse", datatype=DataType.SPARSE_FLOAT_VECTOR)
bm25_function = Function(
name="content_bm25",
input_field_names=["content"],
output_field_names=["sparse"],
function_type=FunctionType.BM25,
)
schema.add_function(bm25_function)
import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import io.milvus.common.clientenum.FunctionType;
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.IndexParam;
import io.milvus.v2.service.collection.request.DropCollectionReq;
import io.milvus.v2.service.collection.request.HasCollectionReq;
import io.milvus.v2.service.vector.request.InsertReq;
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.EmbeddedText;
import io.milvus.v2.service.vector.response.SearchResp;
import java.util.*;
ConnectConfig config = ConnectConfig.builder()
.uri("YOUR_CLUSTER_ENDPOINT")
.build();
MilvusClientV2 client = new MilvusClientV2(config);
String COLLECTION_NAME = "text_bm25_collection";
if (client.hasCollection(HasCollectionReq.builder()
.collectionName(COLLECTION_NAME)
.build())) {
client.dropCollection(DropCollectionReq.builder()
.collectionName(COLLECTION_NAME)
.async(false)
.build());
}
CreateCollectionReq.CollectionSchema schema = CreateCollectionReq.CollectionSchema.builder()
.build();
schema.addField(AddFieldReq.builder()
.fieldName("id")
.dataType(DataType.Int64)
.isPrimaryKey(true)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("content")
.dataType(DataType.Text)
.enableAnalyzer(true)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("sparse")
.dataType(DataType.SparseFloatVector)
.build());
schema.addFunction(CreateCollectionReq.Function.builder()
.name("content_bm25")
.functionType(FunctionType.BM25)
.inputFieldNames(Collections.singletonList("content"))
.outputFieldNames(Collections.singletonList("sparse"))
.build());
import (
"github.com/milvus-io/milvus/client/v3/entity"
"context"
"fmt"
"log"
"github.com/milvus-io/milvus/client/v3/column"
"github.com/milvus-io/milvus/client/v3/index"
"github.com/milvus-io/milvus/client/v3/milvusclient"
)
ctx := context.Background()
const COLLECTION_NAME = "text_bm25_collection"
client, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
Address: "YOUR_CLUSTER_ENDPOINT",
})
if err != nil {
log.Fatal(err)
}
defer client.Close(ctx)
if has, _ := client.HasCollection(ctx, milvusclient.NewHasCollectionOption(COLLECTION_NAME)); has {
_ = client.DropCollection(ctx, milvusclient.NewDropCollectionOption(COLLECTION_NAME))
}
schema := entity.NewSchema().WithDynamicFieldEnabled(false).
WithField(entity.NewField().WithName("id").WithDataType(entity.FieldTypeInt64).WithIsPrimaryKey(true)).
WithField(entity.NewField().WithName("content").WithDataType(entity.FieldTypeText).WithEnableAnalyzer(true)).
WithField(entity.NewField().WithName("sparse").WithDataType(entity.FieldTypeSparseVector)).
WithFunction(entity.NewFunction().
WithName("content_bm25").
WithType(entity.FunctionTypeBM25).
WithInputFields("content").
WithOutputFields("sparse"))
use milvus::v2::prelude::*;
use serde_json::json;
use std::collections::HashMap;
let client = ClientV2::new(
&ConnectConfig::new()
.uri("YOUR_CLUSTER_ENDPOINT")
.token("YOUR_CLUSTER_TOKEN"),
)
.await?;
let collection_name = "text_bm25_collection";
if client
.has_collection(
HasCollectionRequest::builder()
.collection_name(collection_name)
.build()?,
)
.await?
.exists()
{
client
.drop_collection(
DropCollectionRequest::builder()
.collection_name(collection_name)
.build()?,
)
.await?;
}
let schema = CollectionSchema::new()
.add_field(
FieldSchema::new()
.name("id")
.data_type(DataType::Int64)
.primary_key(true),
)
.add_field(
FieldSchema::new()
.name("content")
.data_type(DataType::Text)
.enable_analyzer(true),
)
.add_field(
FieldSchema::new()
.name("sparse")
.data_type(DataType::SparseFloatVector),
)
.add_function(
Function::new()
.name("content_bm25")
.function_type(FunctionType::Bm25)
.input_fields(["content"])
.output_fields(["sparse"]),
);
#include "milvus/MilvusClientV2.h"
#include <iostream>
#include <memory>
#include <string>
#include <utility>
#include <vector>
auto client = milvus::MilvusClientV2::Create();
milvus::ConnectParam connect_param{"YOUR_CLUSTER_ENDPOINT"};
auto status = client->Connect(connect_param);
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
const std::string COLLECTION_NAME = "text_bm25_collection";
milvus::HasCollectionResponse has_response;
status = client->HasCollection(milvus::HasCollectionRequest().WithCollectionName(COLLECTION_NAME), has_response);
if (has_response.Has()) {
status = client->DropCollection(milvus::DropCollectionRequest().WithCollectionName(COLLECTION_NAME));
}
milvus::CollectionSchemaPtr schema = std::make_shared<milvus::CollectionSchema>();
schema->SetEnableDynamicField(false);
schema->AddField(milvus::FieldSchema("id", milvus::DataType::INT64, "", true));
schema->AddField(milvus::FieldSchema("content", milvus::DataType::TEXT).EnableAnalyzer(true));
schema->AddField(milvus::FieldSchema("sparse", milvus::DataType::SPARSE_FLOAT_VECTOR));
auto function = std::make_shared<milvus::Function>("content_bm25", milvus::FunctionType::BM25);
function->AddInputFieldName("content");
function->AddOutputFieldName("sparse");
schema->AddFunction(function);
import { DataType } from "@zilliz/milvus2-sdk-node";
import { MilvusClient, DataType, FunctionType } from "@zilliz/milvus2-sdk-node";
const client = new MilvusClient({ address: "YOUR_CLUSTER_ENDPOINT" });
const COLLECTION_NAME = "text_bm25_collection";
if (await client.hasCollection({ collection_name: COLLECTION_NAME })) {
await client.dropCollection({ collection_name: COLLECTION_NAME });
}
const schema = [
{ name: "id", data_type: DataType.Int64, is_primary_key: true },
{ name: "content", data_type: DataType.Text, enable_analyzer: true },
{ name: "sparse", data_type: DataType.SparseFloatVector }
];
const functions = [{
name: "content_bm25",
type: FunctionType.BM25,
input_field_names: ["content"],
output_field_names: ["sparse"],
params: {}
}];
using Milvus.Client.V2.Types;
using Milvus.Client.V2;
using Milvus.Client.V2.Requests.Collection;
using Milvus.Client.V2.Requests.Dml;
using Milvus.Client.V2.Requests.Dql;
using Milvus.Client.V2.Requests.Index;
using Milvus.Client.V2.Responses.Dql;
var config = new ConnectConfig
{
Uri = "YOUR_CLUSTER_ENDPOINT"
};
using var client = new MilvusClientV2(config);
await client.ConnectAsync();
const string COLLECTION_NAME = "text_bm25_collection";
if ((await client.HasCollectionAsync(new HasCollectionReq { CollectionName = COLLECTION_NAME })).Has)
{
await client.DropCollectionAsync(new DropCollectionReq { CollectionName = COLLECTION_NAME });
}
var schema = new CollectionSchema { Name = COLLECTION_NAME };
schema.Fields.Add(new FieldSchema("id", DataType.Int64, isPrimaryKey: true));
// DataType.Text is an alias of VarChar with analyzer support for full-text search
schema.Fields.Add(FieldSchema.CreateVarchar("content", maxLength: 65535, enableAnalyzer: true, enableMatch: true));
schema.Fields.Add(new FieldSchema("sparse", DataType.SparseFloatVector));
schema.Functions.Add(FunctionSchema.CreateBm25("content_bm25", "content", "sparse"));
export BASE_URL="YOUR_CLUSTER_ENDPOINT"
export TOKEN="YOUR_CLUSTER_TOKEN"
export COLLECTION_NAME="text_bm25_collection"
# Drop an old copy if this example is run repeatedly.
curl --request POST \
--url "${BASE_URL}/v2/vectordb/collections/drop" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d "{\"collectionName\": \"${COLLECTION_NAME}\"}"
export schema='{
"fields": [
{"fieldName": "id", "dataType": "Int64", "isPrimary": true},
{"fieldName": "content", "dataType": "Text", "elementTypeParams": {"enable_analyzer": true}},
{"fieldName": "sparse", "dataType": "SparseFloatVector"}
],
"functions": [
{
"name": "content_bm25",
"type": "BM25",
"inputFieldNames": ["content"],
"outputFieldNames": ["sparse"]
}
]
}'
# Zilliz CLI
ステップ 2: スパースベクトルインデックスを作成する
BM25 関数で生成されたスパースベクトルフィールドにインデックスを作成します。メトリックタイプは BM25 に設定する必要があります。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- CSharp
- cURL
- Zilliz CLI
index_params = client.prepare_index_params()
index_params.add_index(
field_name="sparse",
index_type="SPARSE_INVERTED_INDEX",
metric_type="BM25",
params={
"inverted_index_algo": "DAAT_MAXSCORE",
"bm25_k1": 1.2,
"bm25_b": 0.75,
},
)
client.create_collection(
collection_name=COLLECTION_NAME,
schema=schema,
index_params=index_params,
)
List<IndexParam> indexParams = new ArrayList<>();
Map<String, Object> bm25Params = new HashMap<>();
bm25Params.put("inverted_index_algo", "DAAT_MAXSCORE");
bm25Params.put("bm25_k1", 1.2);
bm25Params.put("bm25_b", 0.75);
indexParams.add(IndexParam.builder()
.fieldName("sparse")
.indexName("sparse_bm25_index")
.indexType(IndexParam.IndexType.SPARSE_INVERTED_INDEX)
.metricType(IndexParam.MetricType.BM25)
.extraParams(bm25Params)
.build());
CreateCollectionReq requestCreate = CreateCollectionReq.builder()
.collectionName("text_bm25_collection")
.collectionSchema(schema)
.indexParams(indexParams)
.build();
client.createCollection(requestCreate);
sparseIndex := milvusclient.NewCreateIndexOption("text_bm25_collection", "sparse",
index.NewGenericIndex("sparse", map[string]string{
index.IndexTypeKey: string(index.SparseInverted),
index.MetricTypeKey: string(entity.BM25),
"inverted_index_algo": "DAAT_MAXSCORE",
"bm25_k1": "1.2",
"bm25_b": "0.75",
})).WithIndexName("sparse_bm25_index")
err = client.CreateCollection(ctx, milvusclient.NewCreateCollectionOption("text_bm25_collection", schema).
WithIndexOptions(sparseIndex))
if err != nil {
fmt.Println(err.Error())
// handle error
}
let index_param = IndexParam::new()
.field_name("sparse")
.index_type(IndexType::SparseInvertedIndex)
.metric_type(MetricType::Bm25)
.extra_params(HashMap::from([
(
"inverted_index_algo".to_string(),
"DAAT_MAXSCORE".to_string(),
),
("bm25_k1".to_string(), "1.2".to_string()),
("bm25_b".to_string(), "0.75".to_string()),
]));
client
.create_collection(
CreateCollectionRequest::builder()
.collection_name(collection_name)
.schema(schema)
.build()?,
)
.await?;
client
.create_index(
CreateIndexRequest::builder()
.collection_name(collection_name)
.index_param(index_param)
.build()?,
)
.await?;
std::vector<milvus::IndexDesc> indexes = {
milvus::IndexDesc("sparse", "sparse_bm25_index", milvus::IndexType::SPARSE_INVERTED_INDEX, milvus::MetricType::BM25)
};
status = client->CreateCollection(milvus::CreateCollectionRequest()
.WithCollectionName("text_bm25_collection")
.WithIndexes(std::move(indexes))
.WithCollectionSchema(schema));
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
const indexParams = [{
field_name: "sparse",
index_name: "sparse_bm25_index",
index_type: "SPARSE_INVERTED_INDEX",
metric_type: "BM25",
params: {
inverted_index_algo: "DAAT_MAXSCORE",
bm25_k1: 1.2,
bm25_b: 0.75
}
}];
const res = await client.createCollection({
collection_name: "text_bm25_collection",
schema: schema,
functions: functions,
index_params: indexParams
});
console.log(res);
var indexParam = new IndexParam(
fieldName: "sparse",
indexType: IndexType.SparseInvertedIndex,
metricType: MetricType.Bm25)
{
ExtraParams =
{
["inverted_index_algo"] = "DAAT_MAXSCORE",
["bm25_k1"] = 1.2,
["bm25_b"] = 0.75
}
};
await client.CreateCollectionAsync(new CreateCollectionReq
{
CollectionName = COLLECTION_NAME,
Schema = schema,
Indexes = [indexParam]
});
export indexParams='[
{
"fieldName": "sparse",
"indexName": "sparse_bm25_index",
"indexType": "SPARSE_INVERTED_INDEX",
"metricType": "BM25",
"params": {
"inverted_index_algo": "DAAT_MAXSCORE",
"bm25_k1": 1.2,
"bm25_b": 0.75
}
}
]'
curl --request POST \
--url "${BASE_URL}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 30" \
-d "{
\"collectionName\": \"text_bm25_collection\",
\"schema\": $schema,
\"indexParams\": $indexParams
}"
# Zilliz CLI
ステップ 3: TEXT データを挿入する
TEXT フィールドにテキストを直接挿入します。sparse フィールドには値を指定しないでください。Milvus は、content に BM25 関数を適用してスパースベクトルを内部的に生成します。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- CSharp
- cURL
- Zilliz CLI
data = [
{
"id": 1,
"content": "Milvus stores vector embeddings and scalar fields in collections. It supports vector search, full text search, and metadata filtering for retrieval applications.",
},
{
"id": 2,
"content": "Long documents are often split into passages before embedding. Store each passage in a TEXT field so search results can return the source text.",
},
{
"id": 3,
"content": "Operational logs and support tickets often contain long natural-language text. TEXT fields can store these values without a fixed max_length setting.",
},
]
client.insert(collection_name=COLLECTION_NAME, data=data)
client.load_collection(collection_name=COLLECTION_NAME)
Gson gson = new Gson();
List<JsonObject> rows = Arrays.asList(
gson.fromJson("{\"id\": 1, \"content\": \"Milvus stores vector embeddings and scalar fields in collections. It supports vector search, full text search, and metadata filtering for retrieval applications.\"}", JsonObject.class),
gson.fromJson("{\"id\": 2, \"content\": \"Long documents are often split into passages before embedding. Store each passage in a TEXT field so search results can return the source text.\"}", JsonObject.class),
gson.fromJson("{\"id\": 3, \"content\": \"Operational logs and support tickets often contain long natural-language text. TEXT fields can store these values without a fixed max_length setting.\"}", JsonObject.class)
);
client.insert(InsertReq.builder()
.collectionName("text_bm25_collection")
.data(rows)
.build());
client.loadCollection(LoadCollectionReq.builder()
.collectionName("text_bm25_collection")
.build());
_, err = client.Insert(ctx, milvusclient.NewColumnBasedInsertOption("text_bm25_collection").
WithInt64Column("id", []int64{1, 2, 3}).
WithColumns(column.NewColumnText("content", []string{
"Milvus stores vector embeddings and scalar fields in collections. It supports vector search, full text search, and metadata filtering for retrieval applications.",
"Long documents are often split into passages before embedding. Store each passage in a TEXT field so search results can return the source text.",
"Operational logs and support tickets often contain long natural-language text. TEXT fields can store these values without a fixed max_length setting.",
})))
if err != nil {
fmt.Println(err.Error())
// handle error
}
_, err = client.LoadCollection(ctx, milvusclient.NewLoadCollectionOption("text_bm25_collection"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
let rows = [
json!({"id": 1, "content": "Milvus stores vector embeddings and scalar fields in collections. It supports vector search, full text search, and metadata filtering for retrieval applications."}),
json!({"id": 2, "content": "Long documents are often split into passages before embedding. Store each passage in a TEXT field so search results can return the source text."}),
json!({"id": 3, "content": "Operational logs and support tickets often contain long natural-language text. TEXT fields can store these values without a fixed max_length setting."}),
];
client
.insert(
InsertRequest::builder()
.collection_name(collection_name)
.rows(rows)
.build()?,
)
.await?;
client
.load_collection(
LoadCollectionRequest::builder()
.collection_name(collection_name)
.build()?,
)
.await?;
milvus::EntityRows rows = {
{{"id", static_cast<int64_t>(1)},
{"content", "Milvus stores vector embeddings and scalar fields in collections. It supports vector search, full text search, and metadata filtering for retrieval applications."}},
{{"id", static_cast<int64_t>(2)},
{"content", "Long documents are often split into passages before embedding. Store each passage in a TEXT field so search results can return the source text."}},
{{"id", static_cast<int64_t>(3)},
{"content", "Operational logs and support tickets often contain long natural-language text. TEXT fields can store these values without a fixed max_length setting."}}
};
milvus::InsertResponse response;
status = client->Insert(milvus::InsertRequest()
.WithCollectionName("text_bm25_collection")
.WithRowsData(std::move(rows)),
response);
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
const data = [
{
id: 1,
content: "Milvus stores vector embeddings and scalar fields in collections. It supports vector search, full text search, and metadata filtering for retrieval applications."
},
{
id: 2,
content: "Long documents are often split into passages before embedding. Store each passage in a TEXT field so search results can return the source text."
},
{
id: 3,
content: "Operational logs and support tickets often contain long natural-language text. TEXT fields can store these values without a fixed max_length setting."
}
];
const res = await client.insert({
collection_name: "text_bm25_collection",
data: data
});
console.log(res);
await client.loadCollection({ collection_name: "text_bm25_collection" });
var contents = new[]
{
"Milvus stores vector embeddings and scalar fields in collections. It supports vector search, full text search, and metadata filtering for retrieval applications.",
"Long documents are often split into passages before embedding. Store each passage in a TEXT field so search results can return the source text.",
"Operational logs and support tickets often contain long natural-language text. TEXT fields can store these values without a fixed max_length setting."
};
await client.InsertAsync(new InsertReq
{
CollectionName = COLLECTION_NAME,
ColumnsData =
[
FieldData.Create("id", new long[] { 1, 2, 3 }),
FieldData.CreateVarChar("content", contents)
]
});
await client.LoadCollectionAsync(new LoadCollectionReq { CollectionName = COLLECTION_NAME });
curl --request POST \
--url "${BASE_URL}/v2/vectordb/entities/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 30" \
-d "{
\"collectionName\": \"${COLLECTION_NAME}\",
\"data\": [
{
\"id\": 1,
\"content\": \"Milvus stores vector embeddings and scalar fields in collections. It supports vector search, full text search, and metadata filtering for retrieval applications.\"
},
{
\"id\": 2,
\"content\": \"Long documents are often split into passages before embedding. Store each passage in a TEXT field so search results can return the source text.\"
},
{
\"id\": 3,
\"content\": \"Operational logs and support tickets often contain long natural-language text. TEXT fields can store these values without a fixed max_length setting.\"
}
]
}"
# Zilliz CLI
ステップ 4: BM25 全文検索を実行する
生のクエリテキストを検索データとして使用し、スパースベクトルフィールドに対して検索します。Milvus はクエリテキストをスパースベクトルに変換し、BM25 で一致をランキングし、要求された TEXT フィールドを output_fields で返します。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- CSharp
- cURL
- Zilliz CLI
results = client.search(
collection_name=COLLECTION_NAME,
data=["how does Milvus store source text for retrieval"],
anns_field="sparse",
limit=2,
output_fields=["content"],
)
SearchResp searchResp = client.search(SearchReq.builder()
.collectionName("text_bm25_collection")
.data(Collections.singletonList(new EmbeddedText("how does Milvus store source text for retrieval")))
.annsField("sparse")
.limit(2)
.outputFields(Collections.singletonList("content"))
.build());
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
"text_bm25_collection",
2,
[]entity.Vector{entity.Text("how does Milvus store source text for retrieval")},
).WithANNSField("sparse").
WithOutputFields("content"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
let response = client
.search(
SearchRequest::builder()
.collection_name(collection_name)
.vector_field("sparse")
.vectors(SearchVectors::EmbeddedText(vec![
"how does Milvus store source text for retrieval".into(),
]))
.output_fields(["content"])
.limit(2)
.build()?,
)
.await?;
std::string query_text = "how does Milvus store source text for retrieval";
auto request = milvus::SearchRequest()
.WithCollectionName("text_bm25_collection")
.WithAnnsField("sparse")
.WithLimit(2)
.AddOutputField("content")
.AddEmbeddedText(query_text);
milvus::SearchResponse search_response;
status = client->Search(request, search_response);
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
}
const res = await client.search({
collection_name: "text_bm25_collection",
data: ["how does Milvus store source text for retrieval"],
anns_field: "sparse",
limit: 2,
output_fields: ["content"]
});
console.log(JSON.stringify(res.results, null, 2));
SearchResp results = await client.SearchAsync(new SearchReq
{
CollectionName = COLLECTION_NAME,
Texts = ["how does Milvus store source text for retrieval"],
VectorFieldName = "sparse",
Limit = 2,
Parameters = new SearchParameters
{
OutputFields = { "content" }
}
});
curl --request POST \
--url "${BASE_URL}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 30" \
-d "{
\"collectionName\": \"${COLLECTION_NAME}\",
\"data\": [\"how does Milvus store source text for retrieval\"],
\"annsField\": \"sparse\",
\"limit\": 2,
\"outputFields\": [\"content\"]
}"
# Zilliz CLI
ステップ 5: 返された TEXT 値を読み取る
各検索ヒットには、BM25 スコアと元の TEXT 値が含まれます。
- Python
- Java
- Go
- Rust
- C++
- NodeJS
- CSharp
- cURL
- Zilliz CLI
for hit in results[0]:
print(f"id: {hit['id']}, score: {hit['distance']}")
print(hit["entity"]["content"])
for (List<SearchResp.SearchResult> hits : searchResp.getSearchResults()) {
for (SearchResp.SearchResult hit : hits) {
System.out.println("id: " + hit.getId() + ", score: " + hit.getScore());
System.out.println(hit.getEntity().get("content"));
}
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs.FieldData().GetScalars())
fmt.Println("Scores: ", resultSet.Scores)
fmt.Println("content: ", resultSet.GetColumn("content"))
}
for result in response.results() {
for row in result.rows()? {
let row = serde_json::Value::Object(row.to_entity_row()?);
println!(
"id: {}, score: {}, content: {}",
row["id"], row["score"], row["content"]
);
}
}
auto search_results = search_response.Results();
for (auto& result : search_results.Results()) {
milvus::EntityRows output_rows;
status = result.OutputRows(output_rows);
if (!status.IsOk()) {
std::cout << status.Message() << std::endl;
continue;
}
for (const auto& row : output_rows) {
std::cout << row << std::endl;
}
}
for (const hit of res.results) {
console.log(`id: ${hit.id}, score: ${hit.score}`);
console.log(hit.content);
}
SingleResult? single = results.SingleResults?.FirstOrDefault();
if (single is not null)
{
for (int i = 0; i < single.Scores.Count; i++)
{
IReadOnlyDictionary<string, object?> row = single.GetRow(i);
long id = results.Ids.LongIds?[i] ?? 0;
Console.WriteLine($"id: {id}, score: {single.Scores[i]}");
Console.WriteLine(row["content"]);
}
}
curl --request POST \
--url "${BASE_URL}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d "{
\"collectionName\": \"text_bm25_collection\",
\"data\": [\"how does Milvus store source text for retrieval\"],
\"annsField\": \"sparse\",
\"limit\": 2,
\"outputFields\": [\"content\"]
}"
# Zilliz CLI
BM25 関数、スパースベクトルインデックス、および全文検索のクエリ構文の詳細については、Full Text Search を参照してください。