コレクションTTLの設定

MilvusはTTL(Time-to-Live)ポリシーにより、エンティティを自動的に失効させることができます。期限切れのエンティティはクエリや検索結果に直ちに表示されなくなり、次のコンパクションサイクル(通常は24時間以内)にストレージから物理的に削除されます。

TTLには2つのモードがあります:

  • コレクションレベルのTTL- すべてのエンティティで共有される1つの保持ウィンドウで、collection.ttl.seconds プロパティで設定します。

  • エンティティレベルのTTL- 各エンティティは、ttl_field プロパティを通じてTTLフィールドとしてマークされた専用のTIMESTAMPTZ フィールドに、独自の絶対的な有効期限を保持します。

この機能は、管理されたコレクションにのみ適用されます。

制限

  • 2つのTTLモードは相互に排他的です。コレクションにcollection.ttl.secondsttl_field の両方を同時に設定することはできません。切り替えるには、2つのモード間の移行を参照してください。

  • コレクションレベルのTTLは、1つのウィンドウをコレクション全体に適用します。1つの行に異なる有効期間が必要な場合は、エンティティレベルTTLを使用します。

  • エンティティレベルTTLのフィールドはTIMESTAMPTZ でなければなりません。他のタイプは拒否される。

  • コレクションごとに1つのTTLフィールド。スキーマには複数のTIMESTAMPTZ フィールドを含めることができますが、ttl_field に名前を付けることができるのは 1 つだけです。

  • ttl_field を削除しても、期限切れエンティティは復活しない。期限切れエンティティを復活させるには、NULL または将来の期限切れタイムスタンプでアップサートを行います。

概要

拡張

TTLを使用する場合

TTLは、保持がポリシーである場合に適したツールです。特定のエンティティが最終的に消滅することを事前に知っていて、cronジョブを記述しなくてもクラスタにそれを強制させたい場合です。

典型的なシナリオ

  • 時間窓付きのデータセット。過去N日間のログ、メトリクス、イベント、短期間のフィーチャーキャッシュのみを保存する。

  • マルチテナントのコレクション。同じコレクションでもテナントによって保持期間が異なります。

  • レコード単位の保持ポリシー。IoTパイプライン、ドキュメントストア、またはMLOpsフィーチャーストアのドキュメントごとのライフタイム。

  • ホットデータとコールドデータの混在。同じコレクション内で、寿命の短いエンティティと長期のエンティティを共存させる。

  • コンプライアンス主導の期限切れ。GDPRスタイルのデータ最小化では、各レコードに独自の「削除期限」が設定されます。

  • ビジネスタイムエクスペリエンス。エンティティは、ある絶対的な瞬間(キャンペーンの終了、セッションの期限切れ)までしか有効でないレコードを表します。

期限切れのエンティティは、検索結果やクエリ結果に表示されません。ただし、24時間以内に実行されるはずのデータ・コンパクションが行われるまでは、ストレージに残っている可能性があります。

Milvus設定ファイルのdataCoord.compaction.expiry.tolerance 設定項目を設定することで、いつデータコンパクションを開始するかを制御することができます。

この設定項目のデフォルトは-1 で、既存のデータ圧縮間隔が適用されることを示しています。しかし、この値を12 のような正の整数に変更すると、エンティティの有効期限が切れた後、指定した時間数後にデータ圧縮が開始されます。

TTLモード

2つのモードは、異なる保持に関する質問に答えます:

  • コレクションレベルのTTLは、すべてのエンティティに単一の保持期間を適用します。各エンティティの有効期限はinsert_ts + ttl_seconds です。

  • Entity-level TTLでは、各エンティティはTIMESTAMPTZ フィールドに自身の絶対的な有効期限を保存する。そのフィールドのNULL は、そのエンティティの有効期限がないことを意味します。

コレクションは一度に1つのモードを使用する。2つのモード間の移行を参照してください。

この表を使用してモードを選択してください:

もしあなたの状況が...

使用

コレクション内のすべてのエンティティが同じ保持ウィンドウに従う必要があります。

コレクションレベルのTTL

保持は "挿入の瞬間からN秒保持"

コレクションレベルのTTL

同じコレクション内で異なるエンティティは異なるライフタイムが必要(テナントごと、ホット/コールド、ドキュメントごと)

エンティティレベルのTTL

保持は絶対壁時計時間(たとえば2027-01-01T00:00:00Z)。

エンティティレベルのTTL

保持は、挿入タイムスタンプではなく、ビジネス・タイムスタンプによって行われる。

エンティティレベルのTTL

挿入後にエンティティの有効期間を更新または延長したい場合

エンティティレベルのTTL

エンティティの中には期限切れにならないものもあれば、期限切れになるものもある

エンティティレベルのTTL (不滅のものにはNULLを使用)

コレクションレベルTTLの設定

コレクション内のすべてのエンティティが同じ保持ウィンドウに従う必要がある場合は、コレクションレベルのTTLを使用します。

新しいコレクションで有効にする

作成時にproperties マップを通してcollection.ttl.seconds (整数、秒単位) を渡す。

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://localhost:19530")

schema = client.create_schema(auto_id=False, enable_dynamic_field=False)
schema.add_field("id", DataType.INT64, is_primary=True, auto_id=False)
schema.add_field("vector", DataType.FLOAT_VECTOR, dim=128)

index_params = client.prepare_index_params()
index_params.add_index(
    field_name="vector", index_type="AUTOINDEX", metric_type="COSINE"
)

client.create_collection(
    collection_name="my_collection",
    schema=schema,
    index_params=index_params,
    properties={
        "collection.ttl.seconds": 1209600  # 14 days
    },
)
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
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;

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

CreateCollectionReq.CollectionSchema schema = CreateCollectionReq.CollectionSchema.builder().build();
schema.addField(AddFieldReq.builder().fieldName("id").dataType(DataType.Int64)
        .isPrimaryKey(true).autoID(false).build());
schema.addField(AddFieldReq.builder().fieldName("vector").dataType(DataType.FloatVector)
        .dimension(128).build());

IndexParam indexParam = IndexParam.builder().fieldName("vector")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .metricType(IndexParam.MetricType.COSINE).build();

Map<String, String> properties = new HashMap<>();
properties.put("collection.ttl.seconds", "1209600"); // 14 days

client.createCollection(CreateCollectionReq.builder()
        .collectionName("my_collection")
        .collectionSchema(schema)
        .indexParams(Collections.singletonList(indexParam))
        .properties(properties)
        .build());
const { MilvusClient, DataType } = require("@zilliz/milvus2-sdk-node");

const client = new MilvusClient({ address: "http://localhost:19530" });

await client.createCollection({
  collection_name: "my_collection",
  fields: [
    { name: "id", data_type: DataType.Int64, is_primary_key: true, autoID: false },
    { name: "vector", data_type: DataType.FloatVector, dim: 128 },
  ],
  index_params: [
    { field_name: "vector", index_type: "AUTOINDEX", metric_type: "COSINE" },
  ],
  properties: {
    "collection.ttl.seconds": 1209600, // 14 days
  },
});
err = client.CreateCollection(ctx, milvusclient.NewCreateCollectionOption("my_collection", schema).
    WithProperty(common.CollectionTTLConfigKey, 1209600)) //  TTL in seconds
if err != nil {
    fmt.Println(err.Error())
    // handle error
}
export params='{
    "ttlSeconds": 1209600
}'

export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
-d "{
    \"collectionName\": \"my_collection\",
    \"schema\": $schema,
    \"params\": $params
}"

既存のコレクションで有効にする

すでに使用されているコレクションにTTLを適用するには、properties マップでcollection.ttl.seconds を使用してalter_collection_properties を呼び出します。

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://localhost:19530")

# Assumes "my_collection" was created earlier without TTL
schema = client.create_schema(auto_id=False, enable_dynamic_field=False)
schema.add_field("id", DataType.INT64, is_primary=True, auto_id=False)
schema.add_field("vector", DataType.FLOAT_VECTOR, dim=128)

index_params = client.prepare_index_params()
index_params.add_index(
    field_name="vector", index_type="AUTOINDEX", metric_type="COSINE"
)

if not client.has_collection("my_collection"):
    client.create_collection(
        collection_name="my_collection",
        schema=schema,
        index_params=index_params,
    )

client.alter_collection_properties(
    collection_name="my_collection",
    properties={"collection.ttl.seconds": 1209600},
)
import java.util.HashMap;
import java.util.Map;

import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.collection.request.AlterCollectionPropertiesReq;

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

// Assumes "my_collection" was created earlier without TTL.

Map<String, String> properties = new HashMap<>();
properties.put("collection.ttl.seconds", "1209600");

client.alterCollectionProperties(AlterCollectionPropertiesReq.builder()
        .collectionName("my_collection")
        .properties(properties)
        .build());
const { MilvusClient } = require("@zilliz/milvus2-sdk-node");

const client = new MilvusClient({ address: "http://localhost:19530" });

// Assumes "my_collection" was created earlier without TTL.
await client.alterCollectionProperties({
  collection_name: "my_collection",
  properties: { "collection.ttl.seconds": 1209600 },
});
err = client.AlterCollectionProperties(ctx, milvusclient.NewAlterCollectionPropertiesOption("my_collection").
    WithProperty(common.CollectionTTLConfigKey, 60))
if err != nil {
    fmt.Println(err.Error())
    // handle error
}
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/alter_properties" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
-d "{
    \"collectionName\": \"my_collection\",
    \"properties\": {
        \"collection.ttl.seconds\": 1209600
    }
}"

TTL設定の削除

コレクション内のデータを無期限に保持することを決定した場合、そのコレクションからTTL設定を削除するだけです。

from pymilvus import MilvusClient

client = MilvusClient(uri="http://localhost:19530")

client.drop_collection_properties(
    collection_name="my_collection",
    property_keys=["collection.ttl.seconds"],
)
import java.util.Collections;

import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.collection.request.DropCollectionPropertiesReq;

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

client.dropCollectionProperties(DropCollectionPropertiesReq.builder()
        .collectionName("my_collection")
        .propertyKeys(Collections.singletonList("collection.ttl.seconds"))
        .build());
const { MilvusClient } = require("@zilliz/milvus2-sdk-node");

const client = new MilvusClient({ address: "http://localhost:19530" });

await client.dropCollectionProperties({
  collection_name: "my_collection",
  properties: ["collection.ttl.seconds"],
});
err = client.DropCollectionProperties(ctx, milvusclient.NewDropCollectionPropertiesOption("my_collection", common.CollectionTTLConfigKey))
if err != nil {
    fmt.Println(err.Error())
    // handle error
}
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/drop_properties" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
-d "{
    \"collectionName\": \"my_collection\",
    \"propertyKeys\": [
        \"collection.ttl.seconds\"
    ]
}"

エンティティレベルのTTL設定Compatible with Milvus 3.0.x

エンティティレベルのTTLは、各エンティティに絶対的な有効期限を持たせます。この時間は、スキーマで宣言した専用のTIMESTAMPTZ 列に格納され、ttl_field コレクションプロパティでその列を TTL フィールドとしてマークします。

新しいコレクションで有効にする

作成時にエンティティレベルのTTLを有効にするには、同じcreate_collection 呼び出しで2つの追加が必要です。スキーマ内のTIMESTAMPTZ フィールドと、そのフィールドを指すttl_field プロパティです。

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://localhost:19530")

schema = client.create_schema(enable_dynamic_field=False)
schema.add_field("id", DataType.INT64, is_primary=True, auto_id=False)
schema.add_field("expire_at", DataType.TIMESTAMPTZ, nullable=True)
schema.add_field("vector", DataType.FLOAT_VECTOR, dim=128)

index_params = client.prepare_index_params()
index_params.add_index(field_name="vector", index_type="AUTOINDEX",
                       metric_type="COSINE")

client.create_collection(
    collection_name="my_collection",
    schema=schema,
    index_params=index_params,
    properties={"ttl_field": "expire_at"},
)
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
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;

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

CreateCollectionReq.CollectionSchema schema = CreateCollectionReq.CollectionSchema.builder().build();
schema.addField(AddFieldReq.builder().fieldName("id").dataType(DataType.Int64)
        .isPrimaryKey(true).autoID(false).build());
schema.addField(AddFieldReq.builder().fieldName("expire_at").dataType(DataType.Timestamptz)
        .isNullable(true).build());
schema.addField(AddFieldReq.builder().fieldName("vector").dataType(DataType.FloatVector)
        .dimension(128).build());

IndexParam indexParam = IndexParam.builder().fieldName("vector")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .metricType(IndexParam.MetricType.COSINE).build();

Map<String, String> properties = new HashMap<>();
properties.put("ttl_field", "expire_at");

client.createCollection(CreateCollectionReq.builder()
        .collectionName("my_collection")
        .collectionSchema(schema)
        .indexParams(Collections.singletonList(indexParam))
        .properties(properties)
        .build());
const { MilvusClient, DataType } = require("@zilliz/milvus2-sdk-node");

const client = new MilvusClient({ address: "http://localhost:19530" });

await client.createCollection({
  collection_name: "my_collection",
  fields: [
    { name: "id", data_type: DataType.Int64, is_primary_key: true, autoID: false },
    { name: "expire_at", data_type: DataType.Timestamptz, nullable: true },
    { name: "vector", data_type: DataType.FloatVector, dim: 128 },
  ],
  index_params: [
    { field_name: "vector", index_type: "AUTOINDEX", metric_type: "COSINE" },
  ],
  properties: { ttl_field: "expire_at" },
});
// go
# restful

コレクションが存在したら、ISO 8601タイムスタンプ文字列を持つエンティティを挿入する。

import random
from pymilvus import MilvusClient

client = MilvusClient(uri="http://localhost:19530")

# Assumes "my_collection" was created earlier with `ttl_field`: "expire_at"
rows = [
    # Never expires
    {"id": 1, "expire_at": None,
     "vector": [random.random() for _ in range(128)]},
    # Expires at 2026-12-31 UTC midnight
    {"id": 2, "expire_at": "2026-12-31T00:00:00Z",
     "vector": [random.random() for _ in range(128)]},
    # Shanghai local time — normalized to UTC internally
    {"id": 3, "expire_at": "2027-01-01T00:00:00+08:00",
     "vector": [random.random() for _ in range(128)]},
]

client.insert("my_collection", rows)
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import com.google.gson.Gson;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;

import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.vector.request.InsertReq;

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

// Assumes "my_collection" was created earlier with `ttl_field`: "expire_at".
Gson gson = new Gson();
Random rng = new Random();

List<Float> vector = new ArrayList<>();
for (int i = 0; i < 128; i++) vector.add(rng.nextFloat());

List<JsonObject> rows = new ArrayList<>();

// Never expires
JsonObject r1 = new JsonObject();
r1.addProperty("id", 1);
r1.add("expire_at", JsonNull.INSTANCE);
r1.add("vector", gson.toJsonTree(vector));
rows.add(r1);

// Expires at 2026-12-31 UTC midnight
JsonObject r2 = new JsonObject();
r2.addProperty("id", 2);
r2.addProperty("expire_at", "2026-12-31T00:00:00Z");
r2.add("vector", gson.toJsonTree(vector));
rows.add(r2);

// Shanghai local time — normalized to UTC internally
JsonObject r3 = new JsonObject();
r3.addProperty("id", 3);
r3.addProperty("expire_at", "2027-01-01T00:00:00+08:00");
r3.add("vector", gson.toJsonTree(vector));
rows.add(r3);

client.insert(InsertReq.builder()
        .collectionName("my_collection")
        .data(rows)
        .build());
const { MilvusClient } = require("@zilliz/milvus2-sdk-node");

const client = new MilvusClient({ address: "http://localhost:19530" });

const vector = Array.from({ length: 128 }, () => Math.random());

// Assumes "my_collection" was created earlier with `ttl_field`: "expire_at".
await client.insert({
  collection_name: "my_collection",
  data: [
    // Never expires
    { id: 1, expire_at: null, vector },
    // Expires at 2026-12-31 UTC midnight
    { id: 2, expire_at: "2026-12-31T00:00:00Z", vector },
    // Shanghai local time — normalized to UTC internally
    { id: 3, expire_at: "2027-01-01T00:00:00+08:00", vector },
  ],
});
// go
# restful

すべてのクエリとベクトル検索で、サーバーはTTLフィルターを自動注入します:

from pymilvus import MilvusClient

client = MilvusClient(uri="http://localhost:19530")

client.load_collection("my_collection")

# Expired rows are filtered out automatically
results = client.query(
    collection_name="my_collection",
    filter="id >= 0",
    output_fields=["id", "expire_at"],
    limit=10,
)
print(results)
import java.util.Arrays;

import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.collection.request.LoadCollectionReq;
import io.milvus.v2.service.vector.request.QueryReq;
import io.milvus.v2.service.vector.response.QueryResp;

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

client.loadCollection(LoadCollectionReq.builder()
        .collectionName("my_collection")
        .build());

// Expired rows are filtered out automatically
QueryResp results = client.query(QueryReq.builder()
        .collectionName("my_collection")
        .filter("id >= 0")
        .outputFields(Arrays.asList("id", "expire_at"))
        .limit(10L)
        .build());
System.out.println(results.getQueryResults());
const { MilvusClient } = require("@zilliz/milvus2-sdk-node");

const client = new MilvusClient({ address: "http://localhost:19530" });

await client.loadCollection({ collection_name: "my_collection" });

// Expired rows are filtered out automatically
const results = await client.query({
  collection_name: "my_collection",
  filter: "id >= 0",
  output_fields: ["id", "expire_at"],
  limit: 10,
});
console.log(results.data);
// go
# restful

同じ自動フィルターがclient.search() にも適用される。

コンパクションによって物理的に削除される前にエンティティの有効期限を延長するには、有効期限タイムスタンプを遅くしてアップサートを行うか、None

import random
from pymilvus import MilvusClient

client = MilvusClient(uri="http://localhost:19530")

client.upsert("my_collection", [
    {"id": 2,
     "vector": [random.random() for _ in range(128)],
     "expire_at": "2028-01-01T00:00:00Z"},
])
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

import com.google.gson.Gson;
import com.google.gson.JsonObject;

import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.vector.request.UpsertReq;

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

Gson gson = new Gson();
Random rng = new Random();
List<Float> vector = new ArrayList<>();
for (int i = 0; i < 128; i++) vector.add(rng.nextFloat());

JsonObject row = new JsonObject();
row.addProperty("id", 2);
row.add("vector", gson.toJsonTree(vector));
row.addProperty("expire_at", "2028-01-01T00:00:00Z");

client.upsert(UpsertReq.builder()
        .collectionName("my_collection")
        .data(Collections.singletonList(row))
        .build());
const { MilvusClient } = require("@zilliz/milvus2-sdk-node");

const client = new MilvusClient({ address: "http://localhost:19530" });

const vector = Array.from({ length: 128 }, () => Math.random());

await client.upsert({
  collection_name: "my_collection",
  data: [
    { id: 2, vector, expire_at: "2028-01-01T00:00:00Z" },
  ],
});
// go
# restful

既存のコレクションで有効にする

コレクションが既に存在し、collection.ttl.seconds が設定されていない場合、add_collection_fieldTIMESTAMPTZ カラムを追加し、alter_collection_properties で TTL フィールドとしてマークします。オプションで、有効期限タイムスタンプを埋め戻すために過去の行をアップサートする - 埋め戻さない行は、NULL 、有効期限が切れることはない。

import random
from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://localhost:19530")

# Step 1 — add a TIMESTAMPTZ column to the schema
client.add_collection_field(
    collection_name="my_collection",
    field_name="expire_at",
    data_type=DataType.TIMESTAMPTZ,
    nullable=True,
)

# Step 2 — mark the new column as the TTL field
client.alter_collection_properties(
    collection_name="my_collection",
    properties={"ttl_field": "expire_at"},
)

# Step 3 (optional) — backfill expiration timestamps for historical rows
client.upsert("my_collection", [
    {"id": 1,
     "vector": [random.random() for _ in range(128)],
     "expire_at": "2026-12-31T00:00:00Z"},
])
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import com.google.gson.Gson;
import com.google.gson.JsonObject;

import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddCollectionFieldReq;
import io.milvus.v2.service.collection.request.AlterCollectionPropertiesReq;
import io.milvus.v2.service.vector.request.UpsertReq;

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

// Step 1 — add a TIMESTAMPTZ column to the schema
client.addCollectionField(AddCollectionFieldReq.builder()
        .collectionName("my_collection")
        .fieldName("expire_at")
        .dataType(DataType.Timestamptz)
        .isNullable(true)
        .build());

// Step 2 — mark the new column as the TTL field
Map<String, String> properties = new HashMap<>();
properties.put("ttl_field", "expire_at");
client.alterCollectionProperties(AlterCollectionPropertiesReq.builder()
        .collectionName("my_collection")
        .properties(properties)
        .build());

// Step 3 (optional) — backfill expiration timestamps for historical rows
Gson gson = new Gson();
Random rng = new Random();
List<Float> vector = new ArrayList<>();
for (int i = 0; i < 128; i++) vector.add(rng.nextFloat());

JsonObject row = new JsonObject();
row.addProperty("id", 1);
row.add("vector", gson.toJsonTree(vector));
row.addProperty("expire_at", "2026-12-31T00:00:00Z");

client.upsert(UpsertReq.builder()
        .collectionName("my_collection")
        .data(Collections.singletonList(row))
        .build());
const { MilvusClient, DataType } = require("@zilliz/milvus2-sdk-node");

const client = new MilvusClient({ address: "http://localhost:19530" });

const vector = Array.from({ length: 128 }, () => Math.random());

// Step 1 — add a TIMESTAMPTZ column to the schema
await client.addCollectionField({
  collection_name: "my_collection",
  field: { name: "expire_at", data_type: DataType.Timestamptz, nullable: true },
});

// Step 2 — mark the new column as the TTL field
await client.alterCollectionProperties({
  collection_name: "my_collection",
  properties: { ttl_field: "expire_at" },
});

// Step 3 (optional) — backfill expiration timestamps for historical rows
await client.upsert({
  collection_name: "my_collection",
  data: [
    { id: 1, vector, expire_at: "2026-12-31T00:00:00Z" },
  ],
});
// go
# restful

TTL設定を削除

property_keysttl_fielddrop_collection_properties を呼び出し、エンティティごとの有効期限を止める。TIMESTAMPTZ カラム自体はスキーマに残ります - 通常のフィールドとしてクエリできます。

from pymilvus import MilvusClient

client = MilvusClient(uri="http://localhost:19530")

client.drop_collection_properties(
    collection_name="my_collection",
    property_keys=["ttl_field"],
)
import java.util.Collections;

import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.collection.request.DropCollectionPropertiesReq;

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

client.dropCollectionProperties(DropCollectionPropertiesReq.builder()
        .collectionName("my_collection")
        .propertyKeys(Collections.singletonList("ttl_field"))
        .build());
const { MilvusClient } = require("@zilliz/milvus2-sdk-node");

const client = new MilvusClient({ address: "http://localhost:19530" });

await client.dropCollectionProperties({
  collection_name: "my_collection",
  properties: ["ttl_field"],
});
// go
# restful

ttl_field を削除すると、今後のクエリの自動フィルタが無効になりますが、すでに期限切れになったエンティティが再び自動的に表示されることはありません。None 同じロードセッション内で期限切れ行へのアクセスを回復する唯一の方法です。

2つのモード間の移行

2つのTTLモードは互いに排他的であるため、切り替えは複数のステップで行います。

コレクションレベルのTTLからエンティティレベルのTTLへの切り替え

コレクションがcollection.ttl.seconds で作成され、エンティティごとの期限切れに切り替えたい場合は、以下の4つのステップに従います。ステップ1をスキップすると、collection TTL is already set, cannot be set ttl field でステップ3が失敗します。

import random
from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://localhost:19530")

# Assumes "my_collection" already exists with `collection.ttl.seconds` set.
# Step 1 — disable collection-level TTL (mandatory; the two modes are mutually exclusive)
client.drop_collection_properties(
    collection_name="my_collection",
    property_keys=["collection.ttl.seconds"],
)

# Step 2 — add a TIMESTAMPTZ column to the schema
client.add_collection_field(
    collection_name="my_collection",
    field_name="expire_at",
    data_type=DataType.TIMESTAMPTZ,
    nullable=True,
)

# Step 3 — set the ttl_field property on the column you just added
client.alter_collection_properties(
    collection_name="my_collection",
    properties={"ttl_field": "expire_at"},
)

# Step 4 (optional) — backfill expiration timestamps for historical entities
client.upsert("my_collection", [
    {"id": 1,
     "vector": [random.random() for _ in range(128)],
     "expire_at": "2026-12-31T00:00:00Z"},
])
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import com.google.gson.Gson;
import com.google.gson.JsonObject;

import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddCollectionFieldReq;
import io.milvus.v2.service.collection.request.AlterCollectionPropertiesReq;
import io.milvus.v2.service.collection.request.DropCollectionPropertiesReq;
import io.milvus.v2.service.vector.request.UpsertReq;

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

// Assumes "my_collection" already exists with `collection.ttl.seconds` set.
// Step 1 — disable collection-level TTL (mandatory; the two modes are mutually exclusive)
client.dropCollectionProperties(DropCollectionPropertiesReq.builder()
        .collectionName("my_collection")
        .propertyKeys(Collections.singletonList("collection.ttl.seconds"))
        .build());

// Step 2 — add a TIMESTAMPTZ column to the schema
client.addCollectionField(AddCollectionFieldReq.builder()
        .collectionName("my_collection")
        .fieldName("expire_at")
        .dataType(DataType.Timestamptz)
        .isNullable(true)
        .build());

// Step 3 — set the ttl_field property on the column you just added
Map<String, String> ttlField = new HashMap<>();
ttlField.put("ttl_field", "expire_at");
client.alterCollectionProperties(AlterCollectionPropertiesReq.builder()
        .collectionName("my_collection")
        .properties(ttlField)
        .build());

// Step 4 (optional) — backfill expiration timestamps for historical entities
Gson gson = new Gson();
Random rng = new Random();
List<Float> vector = new ArrayList<>();
for (int i = 0; i < 128; i++) vector.add(rng.nextFloat());

JsonObject row = new JsonObject();
row.addProperty("id", 1);
row.add("vector", gson.toJsonTree(vector));
row.addProperty("expire_at", "2026-12-31T00:00:00Z");

client.upsert(UpsertReq.builder()
        .collectionName("my_collection")
        .data(Collections.singletonList(row))
        .build());
// nodejs
// go
# restful

expire_at 。バックフィルを行わない履歴エンティティは、その列にNULL 。有限の寿命を持つべき行だけをバックフィルする。

エンティティレベルのTTLからコレクションレベルのTTLへの切り替え

別の方向に進むには、ttl_field を削除し、collection.ttl.seconds を設定する:

from pymilvus import MilvusClient

client = MilvusClient(uri="http://localhost:19530")

# Assumes "my_collection" already exists with `ttl_field` set.
client.drop_collection_properties(
    collection_name="my_collection",
    property_keys=["ttl_field"],
)
client.alter_collection_properties(
    collection_name="my_collection",
    properties={"collection.ttl.seconds": 1209600},  # 14 days
)
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.collection.request.AlterCollectionPropertiesReq;
import io.milvus.v2.service.collection.request.DropCollectionPropertiesReq;

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

// Assumes "my_collection" already exists with `ttl_field` set.
client.dropCollectionProperties(DropCollectionPropertiesReq.builder()
        .collectionName("my_collection")
        .propertyKeys(Collections.singletonList("ttl_field"))
        .build());

Map<String, String> properties = new HashMap<>();
properties.put("collection.ttl.seconds", "1209600"); // 14 days
client.alterCollectionProperties(AlterCollectionPropertiesReq.builder()
        .collectionName("my_collection")
        .properties(properties)
        .build());
// nodejs
// go
# restful

よくある質問

TTL設定によるデータの有効期限はいつですか?

現在のところ、データは挿入またはアップサートされた時点に基づいて失効します。期限切れのデータは検索結果に表示されません。詳しくは例をご覧ください。

期限切れのデータはいつ物理的に削除されますか?

有効期限が切れたデータは検索結果に表示されません。ただし、クラスタのコンパクション・ポリシーに従って、その後のシステム・コンパクションの後にのみ物理的に削除されます。