HGraph is the vector index algorithm in Hologres for approximate nearest neighbor (ANN) search. Use it to build similarity search, image retrieval, and scene recognition applications on top of your existing Hologres tables.
Approximate retrieval functions use the vector index to accelerate queries but may return different results than exact retrieval. The recall rate cannot reach 100%, and a query with LIMIT 1000 may return fewer than 1,000 results.
Usage notes
HGraph is supported in Hologres V4.0 and later.
Vector indexes are supported only on column-oriented tables and hybrid row-column tables. Row-oriented tables do not support vector indexes.
Do not enable the recycle bin feature for tables that have vector indexes if you plan to drop or rebuild them—for example, with
INSERT OVERWRITE. Tables in the recycle bin continue to consume memory.After you create a vector index, the index manifest is built during compaction following data import.
Data in Mem Tables has no vector index. Retrieval requests on Mem Table data use brute-force computation.
For large-scale data import, use Serverless Computing resources. Serverless resources run compaction and index building concurrently during import. For more information, see Use Serverless Computing to execute read/write tasks and Use Serverless Computing to execute compaction tasks.
If you are not using Serverless resources, manually trigger compaction after batch data import or after modifying an index. For more information, see Compact data files (beta).
SELECT hologres.hg_full_compact_table('<SCHEMA_NAME>.<TABLE_NAME>', 'max_file_size_mb=4096');Serverless Computing resources support vector retrieval queries.
Manage vector indexes
Create an index
Create a vector index when you create a table. Vectors in Hologres are stored as float4 arrays. The vector dimension corresponds to the length of the one-dimensional array (array_length).
CREATE TABLE <TABLE_NAME> (
<VECTOR_COLUMN_NAME> float4[] CHECK (array_ndims(<VECTOR_COLUMN_NAME>) = 1 AND array_length(<VECTOR_COLUMN_NAME>, 1) = <DIM>)
)
WITH (
vectors = '{
"<VECTOR_COLUMN_NAME>": {
"algorithm": "<ALGORITHM>",
"distance_method": "<DISTANCE_METHOD>",
"builder_params": {
"<BUILDER_PARAMETERS_NAME>": <VALUE>
[, ...]
}
}
[ , "<VECTOR_COLUMN_NAME_2>": { ... } ]
}'
);Table parameters
| Parameter | Description |
|---|---|
table_name | The name of the target table. |
vector_column_name | The name of the vector column. |
dim | The number of dimensions in the vector column. |
The vectors parameter accepts a JSON-formatted string. At the top level, only one vector_column_name key is allowed to specify the column for which to build the index. The value of that key is a JSON object with the following fields:
| Key | Description |
|---|---|
algorithm | Required. The index algorithm. Only HGraph is supported. |
distance_method | Required. The distance calculation method. Supported values: Euclidean, InnerProduct, Cosine. The distance function used at query time must match this method and meet the corresponding sort order—otherwise the index is not used. |
builder_params | A JSON-formatted string of index building parameters. See the following table. |
Distance methods and required sort order
| Method | Sort order | Example |
|---|---|---|
Euclidean | Ascending only | ORDER BY distance ASC |
InnerProduct | Descending only | ORDER BY distance DESC |
Cosine | Descending only | ORDER BY distance DESC |
Builder parameters
| Parameter | Default | Description |
|---|---|---|
base_quantization_type | — | Required. The quantization method for the low-precision index. Supported values: sq8, sq8_uniform, fp16, fp32, rabitq. See Choose a quantization method. |
max_degree | 64 | The maximum number of neighbors each vertex connects to during index building. A higher value improves search accuracy but increases graph build time and storage. Do not exceed 96. |
ef_construction | 400 | The candidate list size during index building. A higher value improves index accuracy but increases build time. Do not exceed 600. |
use_reorder | FALSE | Whether to enable the high-precision index layer for reranking. |
precise_quantization_type | fp32 | The quantization method for the high-precision index. Effective only when use_reorder is TRUE. Do not modify this value. Supported values: sq8, sq8_uniform, fp16, fp32 (must be higher precision than base_quantization_type). |
precise_io_type | block_memory_io | The storage medium for the hybrid index. Effective only when use_reorder is TRUE. Supported values: block_memory_io (both low-precision and high-precision indexes stored in memory), reader_io (low-precision in memory, high-precision on disk). |
graph_storage_type | flat | Controls graph index compression in memory. Supported values: flat (no compression), compressed (saves 50% memory with approximately 5% QPS reduction). Requires Hologres V4.0.10 or later. |
extra_columns | — | Attaches column values to the index for retrieval without querying the base table. Supported column types: INT, BIGINT, SMALLINT. Supported from Hologres V4.1.1. Example: "extra_columns": "id". |
builder_thread_count | 4 | The number of threads for building the index during writes. Do not modify in most scenarios—increasing this value can cause high CPU utilization. Modifying this parameter does not trigger index rebuilding. |
Modify an index
ALTER TABLE <TABLE_NAME>
SET (
vectors = '{
"<VECTOR_COLUMN_NAME>": {
"algorithm": "<ALGORITHM>",
"distance_method": "<DISTANCE_METHOD>",
"builder_params": {
"<BUILDER_PARAMETERS_NAME>": <VALUE>
[, ...]
}
}
}'
);Delete an index
-- Delete vector indexes for all columns in the table
ALTER TABLE <TABLE_NAME>
SET (
vectors = '{}'
);
-- If col1 and col2 both have vector indexes and you need to delete only the index for col2,
-- use ALTER TABLE to retain only the index for col1.
ALTER TABLE <TABLE_NAME>
SET (
vectors = '{
"col1": { ... }
}'
);View an index
Query the hologres.hg_table_properties system table to view created vector indexes.
SELECT
*
FROM
hologres.hg_table_properties
WHERE
table_name = '<TABLE_NAME>'
AND property_key = 'vectors';Run vector retrieval queries
Approximate vs. exact retrieval
Hologres supports both approximate and exact vector retrieval. Only approximate retrieval functions can use the vector index to accelerate queries. The approximate function used in a query must match the distance_method of the index and respect the required sort order—otherwise the index is not used.
Vector distance functions
| Function | Retrieval type | Input | Return | Notes |
|---|---|---|---|---|
approx_euclidean_distance | Approximate | float4[], float4[] | float4 | Uses vector index; must match distance_method: Euclidean |
approx_inner_product_distance | Approximate | float4[], float4[] | float4 | Uses vector index; must match distance_method: InnerProduct |
approx_cosine_distance | Approximate | float4[], float4[] | float4 | Uses vector index; must match distance_method: Cosine |
euclidean_distance | Exact | float4[], float4[] | float4 | Does not use vector index |
inner_product_distance | Exact | float4[], float4[] | float4 | Does not use vector index |
cosine_distance | Exact | float4[], float4[] | float4 | Does not use vector index |
Distance functions do not support all-constant input parameters.
Verify that the index is used
Run EXPLAIN or EXPLAIN ANALYZE on your query to check whether the execution plan uses the vector index. If the plan contains Vector Filter, the index is active.
Example query:
SELECT
id,
approx_euclidean_distance(feature, '{0.1,0.2,0.3,0.4}') AS distance
FROM
feature_tb
ORDER BY
distance
LIMIT 40;Example execution plan (index is used):
Limit (cost=0.00..182.75 rows=40 width=12)
-> Sort (cost=0.00..182.75 rows=160 width=12)
Sort Key: (VectorDistanceRef)
-> Gather (cost=0.00..181.95 rows=160 width=12)
-> Limit (cost=0.00..181.94 rows=160 width=12)
-> Sort (cost=0.00..181.94 rows=40000 width=12)
Sort Key: (VectorDistanceRef)
-> Local Gather (cost=0.00..91.53 rows=40000 width=12)
-> Limit (cost=0.00..91.53 rows=40000 width=12)
-> Sort (cost=0.00..91.53 rows=40000 width=12)
Sort Key: (VectorDistanceRef)
-> Project (cost=0.00..1.12 rows=40000 width=12)
-> Index Scan using Clustering_index on feature_tb (cost=0.00..1.00 rows=40000 width=8)
Vector Filter: VectorCond => KNN: '40'::bigint distance_method: approx_euclidean_distance search_params: {NULL} args: {feature'{0.100000001,0.200000003,0.300000012,0.400000006}'::real[]}
Query Queue: init_warehouse.default_queue
Optimizer: HQO version 4.0.0End-to-end example
The following example creates a table with a vector index, imports data using Serverless Computing resources, and runs both approximate and exact retrieval queries.
Step 1: Create the table
-- Create a table group with shard count = 4
CALL HG_CREATE_TABLE_GROUP ('test_tg_shard_4', 4);
-- Create a table with a HGraph vector index
CREATE TABLE feature_tb (
id bigint NOT NULL,
feature float4[] CHECK(array_ndims(feature) = 1 AND array_length(feature, 1) = 4)
)
WITH (
table_group = 'test_tg_shard_4',
vectors = '{
"feature": {
"algorithm": "HGraph",
"distance_method": "Cosine",
"builder_params": {
"base_quantization_type": "rabitq",
"graph_storage_type": "compressed",
"max_degree": 64,
"ef_construction": 400,
"precise_quantization_type": "fp32",
"use_reorder": true,
"extra_columns": "id",
"max_total_size_to_merge_mb": 4096
}
}
}'
);Step 2: Import data
-- Use Serverless Computing for large-scale data import.
-- This completes compaction and index building concurrently during import.
SET hg_computing_resource = 'serverless';
SET hg_serverless_computing_run_compaction_before_commit_bulk_load = on;
INSERT INTO feature_tb
SELECT i, array[random(), random(), random(), random()]::float4[]
FROM generate_series(1, 100000) i;
-- Reset after import so that subsequent queries do not use Serverless resources unnecessarily.
RESET hg_computing_resource;Step 3: Run approximate retrieval
-- Return the top 40 results by cosine distance
SELECT
id,
approx_cosine_distance(feature, '{0.1,0.2,0.3,0.4}') AS distance
FROM
feature_tb
ORDER BY
distance DESC
LIMIT 40;Because this table uses"extra_columns": "id", the query retrievesidvalues directly from the vector index without reading the base table column. Check thevector_index_extra_columns_usedfield inEXPLAIN ANALYZEoutput to see how many manifest files served values throughextra_columns.
Step 4: Run exact retrieval
-- Exact retrieval does not use the vector index.
-- The distance function does not need to match the index's distance_method.
SELECT
id,
cosine_distance(feature, '{0.1,0.2,0.3,0.4}') AS distance
FROM
feature_tb
ORDER BY
distance DESC
LIMIT 40;Performance tuning
When to use a vector index
For small data volumes—for example, tens of thousands of records—or when your instance has ample compute resources, skip the vector index and use brute-force (exact) computation. Add a vector index only when exact retrieval cannot meet your latency, throughput, or scalability requirements.
Keep in mind that vector indexes are inherently approximate:
The recall rate cannot reach 100%.
A query with
LIMIT 1000may return fewer than 1,000 results.
Choose a quantization method
base_quantization_type controls the trade-off between memory usage, query speed, and recall accuracy. Supported values are: sq8, sq8_uniform, fp16, fp32, and rabitq. Higher-precision quantization types use more memory but yield higher recall accuracy; lower-precision types use less memory and improve query speed at the cost of some accuracy.
For latency-sensitive workloads with full in-memory indexes, use sq8_uniform or rabitq. For large datasets with hybrid memory-disk indexes, use rabitq. When using rabitq, enabling use_reorder: true with precise_quantization_type: fp32 can improve recall accuracy.
Choose an index configuration for your workload
For a single table, single column, 768-dimensional vector index, use the following configurations as a starting point.
| Workload | Index type | Quantization | Max rows per shard |
|---|---|---|---|
| Latency-sensitive | Full in-memory | sq8_uniform or rabitq | 5 million |
| Large data volume or latency-insensitive | Hybrid memory-disk | rabitq | 30–50 million |
For multiple vector columns on the same table, reduce the per-shard row limits proportionally. Vector dimension size also affects these limits.
Full in-memory index example
CREATE TABLE feature_tb (
id bigint NOT NULL,
feature float4[] CHECK(array_ndims(feature) = 1 AND array_length(feature, 1) = 4)
)
WITH (
table_group = 'test_tg_shard_4',
vectors = '{
"feature": {
"algorithm": "HGraph",
"distance_method": "Cosine",
"builder_params": {
"base_quantization_type": "sq8_uniform",
"graph_storage_type": "compressed",
"max_degree": 64,
"ef_construction": 400,
"precise_quantization_type": "fp32",
"use_reorder": true,
"max_total_size_to_merge_mb": 4096
}
}
}'
);Hybrid memory-disk index example
CREATE TABLE feature_tb (
id bigint NOT NULL,
feature float4[] CHECK(array_ndims(feature) = 1 AND array_length(feature, 1) = 4)
)
WITH (
table_group = 'test_tg_shard_4',
vectors = '{
"feature": {
"algorithm": "HGraph",
"distance_method": "Cosine",
"builder_params": {
"base_quantization_type": "rabitq",
"graph_storage_type": "compressed",
"max_degree": 64,
"ef_construction": 400,
"precise_quantization_type": "fp32",
"precise_io_type": "reader_io",
"use_reorder": true,
"max_total_size_to_merge_mb": 4096
}
}
}'
);Tune recall rate
The following index parameters achieve a default recall rate above 95% on the VectorDBBench dataset:
base_quantization_type:rabitqorsq8_uniformprecise_quantization_type:fp32max_degree: 64ef_construction: 400
At query time, the Grand Unified Configuration (GUC) parameter hg_vector_ef_search controls the candidate list size during retrieval. The default value is 80, which balances accuracy and resource usage.
To push recall above 99%, increase hg_vector_ef_search while keeping index parameters unchanged:
SET hg_vector_ef_search = 400;To achieve 99.5%–99.7% recall, adjust both the index build parameters and the query parameter together. This increases query latency, query resource usage, index build time, and index build resource usage:
max_degree: 96ef_construction: 500 or 600hg_vector_ef_search: 500 or 600
Set an appropriate shard count
More shards produce more manifest files, which reduces approximate query throughput. Follow these guidelines:
Size compute resources to your data. For 768-dimensional vectors: For other vector dimensions, see Recommended instance types for vector computing.
Full in-memory index: up to 5 million vectors per worker.
Hybrid memory-disk index: up to 100 million vectors per worker.
Set shard count equal to the number of workers. For a 64 CU instance, set
shard_countto 4.
-- Create a table group with shard count = 4
CALL HG_CREATE_TABLE_GROUP ('test_tg_shard_4', 4);
CREATE TABLE feature_tb (
id bigint NOT NULL,
feature float4[] CHECK(array_ndims(feature) = 1 AND array_length(feature, 1) = 4)
)
WITH (
table_group = 'test_tg_shard_4',
vectors = '{
"feature": {
"algorithm": "HGraph",
"distance_method": "Cosine",
"builder_params": {
"base_quantization_type": "sq8_uniform",
"graph_storage_type": "compressed",
"max_degree": 64,
"ef_construction": 400,
"precise_quantization_type": "fp32",
"use_reorder": true,
"max_total_size_to_merge_mb": 4096
}
}
}'
);Vector and scalar hybrid queries
For queries that combine vector retrieval with scalar filter conditions, the typical patterns are:
Filter by a string column (e.g., organization or group ID)
A common use case is retrieving vectors within a specific group—for example, facial recognition data for students in a particular class.
SELECT <distance_function>(feature, '{1,2,3,4}') AS d
FROM feature_tb
WHERE uuid = 'x'
ORDER BY d
LIMIT 10;Optimize by:
Setting
uuidas the distribution key. This ensures all data for the same filter value lands in the same shard, so the query touches only one shard.Setting
uuidas the clustering key. This sorts data within files byuuid, reducing the scan range.
Filter by a time field
SELECT <distance_function>(feature, '{1,2,3,4}') AS d
FROM feature_tb
WHERE time_field BETWEEN '2020-08-30 00:00:00' AND '2020-08-30 12:00:00'
ORDER BY d
LIMIT 10;Set time_field as the segment key. This lets Hologres quickly locate the relevant data files by time range.
Recommended table structure for hybrid queries
-- Remove time_field and its segment_key if you do not filter by time.
CREATE TABLE feature_tb (
time_field timestamptz NOT NULL,
uuid text NOT NULL,
feature float4[] CHECK(array_ndims(feature) = 1 AND array_length(feature, 1) = 4)
)
WITH (
distribution_key = 'uuid',
segment_key = 'time_field',
clustering_key = 'uuid',
vectors = '{
"feature": {
"algorithm": "HGraph",
"distance_method": "Cosine",
"builder_params": {
"base_quantization_type": "sq8_uniform",
"graph_storage_type": "compressed",
"max_degree": 64,
"ef_construction": 400,
"precise_quantization_type": "fp32",
"use_reorder": true,
"max_total_size_to_merge_mb": 4096
}
}
}'
);Rebuild indexes using Serverless resources
Some property changes trigger compaction and index rebuilding, which can spike CPU usage. Handle these changes as follows:
Changes to `bitmap_columns`, `dictionary_encoding_columns`, or vector indexes
Use the REBUILD syntax with Serverless Computing resources instead of ALTER TABLE ... SET. For more information, see REBUILD.
ASYNC REBUILD TABLE <table_name>
WITH (
rebuild_guc_hg_computing_resource = 'serverless'
)
SET (
bitmap_columns = '<col1>,<col2>',
dictionary_encoding_columns = '<col1>:on,<col2>:off',
vectors = '{
"<col_vector>": {
"algorithm": "HGraph",
"distance_method": "Cosine",
"builder_params": {
"base_quantization_type": "rabitq",
"graph_storage_type": "compressed",
"max_degree": 64,
"ef_construction": 400,
"precise_quantization_type": "fp32",
"use_reorder": true,
"max_total_size_to_merge_mb": 4096
}
}
}'
);Changes to columnar storage for JSON data or full-text index columns
The REBUILD syntax is not yet supported for these changes. Use a temporary table instead:
BEGIN;
-- Clean up any existing temporary table
DROP TABLE IF EXISTS <table_new>;
-- Create a temporary table with the same structure
SET hg_experimental_enable_create_table_like_properties = on;
CALL HG_CREATE_TABLE_LIKE ('<table_new>', 'select * from <table>');
COMMIT;
-- Apply the new column properties to the temporary table
ALTER TABLE <table_new> ALTER COLUMN <column_name> SET (enable_columnar_type = ON);
CREATE INDEX <idx_name> ON <table_new> USING FULLTEXT (column_name);
-- Insert data using Serverless resources (index building completes synchronously)
SET hg_computing_resource = 'serverless';
INSERT INTO <table_new> SELECT * FROM <table>;
ANALYZE <table_new>;
BEGIN;
-- Replace the original table with the temporary table
DROP TABLE IF EXISTS <table>;
ALTER TABLE <table_new> RENAME TO <table>;
COMMIT;Other property changes (e.g., `distribution_key`, `clustering_key`, `segment_key`, storage format)
Use the REBUILD syntax with Serverless Computing resources.
FAQ
Why isn't the vector index being used?
Common causes:
The distance function in your query does not match the
distance_methodof the index. For example, usingapprox_cosine_distanceon an index created withdistance_method: Euclideandoes not use the index.The
ORDER BYdirection does not match the method's required sort order. Euclidean distance requiresASC; inner product and cosine distance requireDESC.The table or column does not have a vector index, or the index has not been built yet (compaction has not run).
Run EXPLAIN on your query and check for Vector Filter in the execution plan to confirm whether the index is active.
Error: `Writing column: feature with array size: 5 violates fixed size list (4) constraint declared in schema`
The dimension of the data you are writing does not match the dimension defined in the table schema. Check your data for rows with incorrect array lengths.
Error: `The size of two array must be the same in DistanceFunction, size of left array: 4, size of right array: x`
The left and right arrays in xx_distance(left, right) have different dimensions. Make sure the query vector has the same number of dimensions as the stored vectors.
How do I write vector data using Java?
private static void insertIntoVector(Connection conn) throws Exception {
try (PreparedStatement stmt = conn.prepareStatement("INSERT INTO feature_tb VALUES(?,?);")) {
for (int i = 0; i < 100; ++i) {
stmt.setInt(1, i);
Float[] featureVector = {0.1f, 0.2f, 0.3f, 0.4f};
Array array = conn.createArrayOf("FLOAT4", featureVector);
stmt.setArray(2, array);
stmt.execute();
}
}
}How do I migrate from a Proxima Graph index to an HGraph index?
Delete the existing Proxima Graph index:
CALL set_table_property ('<TABLE_NAME>', 'proxima_vectors', '{}');Replace
<TABLE_NAME>with the actual table name.Create a new HGraph index using
CREATE TABLEorALTER TABLE. For instructions, see Create an index.