All Products
Search
Document Center

Hologres:Work with HGraph for vector search

Last Updated:Mar 26, 2026

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.

Important

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

ParameterDescription
table_nameThe name of the target table.
vector_column_nameThe name of the vector column.
dimThe 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:

KeyDescription
algorithmRequired. The index algorithm. Only HGraph is supported.
distance_methodRequired. 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_paramsA JSON-formatted string of index building parameters. See the following table.

Distance methods and required sort order

MethodSort orderExample
EuclideanAscending onlyORDER BY distance ASC
InnerProductDescending onlyORDER BY distance DESC
CosineDescending onlyORDER BY distance DESC

Builder parameters

ParameterDefaultDescription
base_quantization_typeRequired. The quantization method for the low-precision index. Supported values: sq8, sq8_uniform, fp16, fp32, rabitq. See Choose a quantization method.
max_degree64The 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_construction400The candidate list size during index building. A higher value improves index accuracy but increases build time. Do not exceed 600.
use_reorderFALSEWhether to enable the high-precision index layer for reranking.
precise_quantization_typefp32The 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_typeblock_memory_ioThe 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_typeflatControls 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_columnsAttaches 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_count4The 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

FunctionRetrieval typeInputReturnNotes
approx_euclidean_distanceApproximatefloat4[], float4[]float4Uses vector index; must match distance_method: Euclidean
approx_inner_product_distanceApproximatefloat4[], float4[]float4Uses vector index; must match distance_method: InnerProduct
approx_cosine_distanceApproximatefloat4[], float4[]float4Uses vector index; must match distance_method: Cosine
euclidean_distanceExactfloat4[], float4[]float4Does not use vector index
inner_product_distanceExactfloat4[], float4[]float4Does not use vector index
cosine_distanceExactfloat4[], float4[]float4Does 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.0

End-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 retrieves id values directly from the vector index without reading the base table column. Check the vector_index_extra_columns_used field in EXPLAIN ANALYZE output to see how many manifest files served values through extra_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 1000 may 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.

WorkloadIndex typeQuantizationMax rows per shard
Latency-sensitiveFull in-memorysq8_uniform or rabitq5 million
Large data volume or latency-insensitiveHybrid memory-diskrabitq30–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: rabitq or sq8_uniform

  • precise_quantization_type: fp32

  • max_degree: 64

  • ef_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:

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: 96

  • ef_construction: 500 or 600

  • hg_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:

  1. 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.

  2. Set shard count equal to the number of workers. For a 64 CU instance, set shard_count to 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 uuid as 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 uuid as the clustering key. This sorts data within files by uuid, 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_method of the index. For example, using approx_cosine_distance on an index created with distance_method: Euclidean does not use the index.

  • The ORDER BY direction does not match the method's required sort order. Euclidean distance requires ASC; inner product and cosine distance require DESC.

  • 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?

  1. Delete the existing Proxima Graph index:

    CALL set_table_property ('<TABLE_NAME>', 'proxima_vectors', '{}');

    Replace <TABLE_NAME> with the actual table name.

  2. Create a new HGraph index using CREATE TABLE or ALTER TABLE. For instructions, see Create an index.

What's next