Skip to content
Open
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
49 changes: 46 additions & 3 deletions docs/docs/primary-key-table/global-index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ Vector additionally requires:
- `deletion-vectors.enabled = true`, except for `first-row`, where it must be `false`.
- The configured ANN implementation on every writer and reader classpath.

Exactly one vector column is currently supported per table.
Multiple vector columns are supported. Each column owns an independent index with its own
dimension, ANN implementation, distance metric, and build options.

</TabItem>

Expand Down Expand Up @@ -265,11 +266,41 @@ schema validation.

</details>

### Index Multiple Vector Columns

List the vector columns in `pk-vector.index.columns` and configure each column separately.
For example, this Flink table indexes image and text embeddings independently:

```sql
CREATE TABLE multimodal_items (
id BIGINT,
image_embedding ARRAY<FLOAT> COMMENT '__VECTOR_FIELD;512',
text_embedding ARRAY<FLOAT> COMMENT '__VECTOR_FIELD;768',
PRIMARY KEY (id) NOT ENFORCED
) WITH (
'bucket' = '8',
'deletion-vectors.enabled' = 'true',
'pk-vector.index.columns' = 'image_embedding,text_embedding',
'fields.image_embedding.pk-vector.index.type' = 'ivf-flat',
'fields.image_embedding.pk-vector.distance.metric' = 'cosine',
'fields.image_embedding.pk-vector.index.options' = '{"nlist":"256"}',
'fields.text_embedding.pk-vector.index.type' = 'ivf-flat',
'fields.text_embedding.pk-vector.distance.metric' = 'inner_product',
'fields.text_embedding.pk-vector.index.options' = '{"nlist":"512"}'
);
```

Each vector search selects one column and uses that column's index, dimension, and distance
metric. Listing multiple columns does not combine their vectors or define a fused ranking.
Index coverage is tracked separately for each column, so an index on `image_embedding` does
not cover a query on `text_embedding`.

### Options

| Option | Default | Description |
|---|---|---|
| `pk-vector.index.columns` | Not set | Vector column to index. Exactly one vector column is currently supported. |
| `pk-index.build.parallelism` | `1` | Maximum concurrent primary-key index build tasks per writer instance. Must be positive. |
| `pk-vector.index.columns` | Not set | Comma-separated vector columns which own independent vector indexes. |
| `fields.<column>.pk-vector.index.type` | Required | ANN implementation, such as `ivf-flat`, `ivf-pq`, `ivf-sq`, `ivf-rq`, or `diskann`. |
| `fields.<column>.pk-vector.distance.metric` | `inner_product` | Distance metric: `l2`, `cosine`, or `inner_product`. |
| `fields.<column>.pk-vector.index.options` | Not set | JSON object containing build options for the selected ANN implementation. |
Expand Down Expand Up @@ -300,6 +331,18 @@ in the [`paimon-full-text` README](https://github.com/apache/paimon/blob/master/

## Maintenance and Coverage

Set `pk-index.build.parallelism` to `2`, for example, to allow two primary-key index build tasks
to run concurrently within one writer instance. The default is `1`. Vector, Full Text, BTree,
Bitmap, Multivalue, and FM indexes share this limit across that writer's columns and buckets.
It is not the Flink or Spark job parallelism.

Blocking commits start all configured indexes before waiting for their results. Non-blocking
commits start builds and collect finished results without waiting; outstanding builds are
collected by later commits. If an index fails during preparation, the coordinator rolls back
that preparation, cancels outstanding builds, and cleans up uncommitted outputs. Previously
committed snapshots remain valid. More concurrent builds can increase memory and I/O usage;
each index implementation may also use its own internal threads.

Paimon builds primary-key indexes from complete `COMPACT` data files above Level 0. An index group
stores the source file names and row counts required to map index results back to physical rows.
Data-file and index-file changes are committed in the same snapshot.
Expand Down Expand Up @@ -610,7 +653,7 @@ create a table with the desired definition and migrate the data.
- Multivalue supports arrays of scalar element types accepted by the global-index key serializer.
Null elements are not indexed. Higher array and element cardinality increases the expanded-sort
I/O and index-file size.
- Exactly one vector index column is currently supported per table.
- Vector indexes are single-column indexes; each configured vector column has an independent index.
- Exactly one full-text index column is currently supported per table.
- Only `FLOAT` vectors are supported.
- Indexes are built from eligible compact output, not directly from Level-0 appends.
Expand Down
8 changes: 7 additions & 1 deletion docs/generated/core_configuration.html
Original file line number Diff line number Diff line change
Expand Up @@ -1392,6 +1392,12 @@
<td>String</td>
<td>Comma-separated character columns indexed by primary-key full-text indexes. The first release supports exactly one column.</td>
</tr>
<tr>
<td><h5>pk-index.build.parallelism</h5></td>
<td style="word-wrap: break-word;">1</td>
<td>Integer</td>
<td>The maximum number of concurrent primary-key index build tasks per writer instance, shared by its index columns and buckets. Must be greater than zero. Increasing this value may increase memory and I/O usage.</td>
</tr>
<tr>
<td><h5>pk-multivalue.index.columns</h5></td>
<td style="word-wrap: break-word;">(none)</td>
Expand All @@ -1402,7 +1408,7 @@
<td><h5>pk-vector.index.columns</h5></td>
<td style="word-wrap: break-word;">(none)</td>
<td>String</td>
<td>Comma-separated VECTOR columns indexed by primary-key vector indexes. Each column owns one index and must define fields.&lt;column&gt;.pk-vector.index.type. Index options and distance metric are also field-scoped. The first release supports exactly one column.</td>
<td>Comma-separated VECTOR columns indexed by primary-key vector indexes. Each column owns one index and must define fields.&lt;column&gt;.pk-vector.index.type. Index options and distance metric are also field-scoped.</td>
</tr>
<tr>
<td><h5>postpone.batch-write-fixed-bucket</h5></td>
Expand Down
32 changes: 21 additions & 11 deletions paimon-api/src/main/java/org/apache/paimon/CoreOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -3163,6 +3163,16 @@ public String toString() {
"The batch size for lateral vector search. Each batch executes vector "
+ "topK search and table lookup for multiple query vectors.");

public static final ConfigOption<Integer> PK_INDEX_BUILD_PARALLELISM =
key("pk-index.build.parallelism")
.intType()
.defaultValue(1)
.withDescription(
"The maximum number of concurrent primary-key index build tasks per "
+ "writer instance, shared by its index columns and buckets. "
+ "Must be greater than zero. Increasing this value may increase "
+ "memory and I/O usage.");

public static final ConfigOption<String> PK_VECTOR_INDEX_COLUMNS =
key("pk-vector.index.columns")
.stringType()
Expand All @@ -3171,8 +3181,7 @@ public String toString() {
"Comma-separated VECTOR columns indexed by primary-key vector indexes. "
+ "Each column owns one index and must define "
+ "fields.<column>.pk-vector.index.type. Index options and distance "
+ "metric are also field-scoped. The first release supports exactly "
+ "one column.");
+ "metric are also field-scoped.");

public static final ConfigOption<String> PK_BTREE_INDEX_COLUMNS =
key("pk-btree.index.columns")
Expand Down Expand Up @@ -4991,6 +5000,16 @@ public boolean primaryKeyFMIndexEnabled() {
return options.getOptional(PK_FM_INDEX_COLUMNS).isPresent();
}

public int primaryKeyIndexBuildParallelism() {
int parallelism = options.get(PK_INDEX_BUILD_PARALLELISM);
checkArgument(
parallelism > 0,
"%s must be greater than zero, but is %s.",
PK_INDEX_BUILD_PARALLELISM.key(),
parallelism);
return parallelism;
}

public List<String> primaryKeyVectorIndexColumns() {
return primaryKeyIndexColumns(PK_VECTOR_INDEX_COLUMNS);
}
Expand Down Expand Up @@ -5122,15 +5141,6 @@ private Options primaryKeySortedIndexOptions(
return resolved;
}

public String primaryKeyVectorIndexColumn() {
List<String> columns = primaryKeyVectorIndexColumns();
checkArgument(
columns.size() == 1,
"pk-vector.index.columns must contain exactly one column in the first release, but is %s.",
columns);
return columns.get(0);
}

@Nullable
public String primaryKeyVectorIndexType(String column) {
return options.get("fields." + column + ".pk-vector.index.type");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public String identifier() {

@Override
public GlobalIndexer create(List<DataField> indexFields, Options options) {
String metric = options.getString(IDENTIFIER + ".metric", null);
if (metric != null) {
options = new Options(options.toMap());
options.setString(TestVectorGlobalIndexer.OPT_METRIC, metric);
}
if (indexFields.size() == 1) {
return new TestVectorGlobalIndexer(indexFields.get(0).type(), options);
}
Expand Down
Loading
Loading