O HGraph é o algoritmo de índice vetorial do Hologres para busca aproximada de vizinhos mais próximos (ANN). Use-o para criar aplicações de busca por similaridade, recuperação de imagens e reconhecimento de cenas em suas tabelas existentes no Hologres.
As funções de recuperação aproximada usam o índice vetorial para acelerar consultas, mas podem retornar resultados diferentes da recuperação exata. A taxa de recall não atinge 100% e uma consulta com LIMIT 1000 pode retornar menos de 1.000 resultados.
Observações de uso
O Hologres V4.0 e versões posteriores oferecem suporte ao HGraph.
Índices vetoriais são compatíveis apenas com tabelas orientadas a colunas e tabelas híbridas de linhas e colunas. Tabelas orientadas a linhas não aceitam índices vetoriais.
Não ative a lixeira para tabelas com índices vetoriais se você planeja excluí-las ou reconstruí-las — por exemplo, com
INSERT OVERWRITE. Tabelas na lixeira continuam consumindo memória.Após a criação de um índice vetorial, o manifesto do índice é gerado durante a compactação subsequente à importação de dados.
Dados em Mem Tables não possuem índice vetorial. Solicitações de recuperação em dados de Mem Table usam computação por força bruta.
Para importação de dados em grande escala, use recursos de Serverless Computing. Esses recursos executam compactação e construção de índice simultaneamente durante a importação. Para mais informações, consulte Executar tarefas de leitura e gravação com serverless computing e Transferir compactação para recursos serverless.
-
Se não estiver usando recursos Serverless, acione manualmente a compactação após a importação de dados em lote ou após modificar um índice. Para mais informações, consulte
SELECT hologres.hg_full_compact_table('<SCHEMA_NAME>.<TABLE_NAME>', 'max_file_size_mb=4096'); Recursos de Serverless Computing aceitam consultas de busca vetorial.
Gerencie índices vetoriais
Crie um índice
Crie um índice vetorial ao criar uma tabela. O Hologres armazena vetores como arrays float4. A dimensão do vetor corresponde ao comprimento do array unidimensional (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>": { ... } ]
}'
);
Parâmetros da tabela
|
Parâmetro |
Descrição |
|
|
Nome da tabela de destino. |
|
|
Nome da coluna vetorial. |
|
|
Número de dimensões na coluna vetorial. |
O parâmetro vectors aceita uma string formatada em JSON. No nível superior, permita apenas uma chave vector_column_name para especificar a coluna onde construir o índice. O valor dessa chave é um objeto JSON com os seguintes campos:
|
Chave |
Descrição |
|
|
Obrigatório. Algoritmo do índice. Apenas |
|
|
Obrigatório. Método de cálculo de distância. Valores aceitos: |
|
|
String formatada em JSON com parâmetros de construção do índice. Consulte a tabela a seguir. |
Métodos de distância e ordem de classificação obrigatória
|
Método |
Ordem de classificação |
Exemplo |
|
|
Apenas ascendente |
|
|
|
Apenas descendente |
|
|
|
Apenas descendente |
|
Parâmetros de construção
|
Parâmetro |
Padrão |
Descrição |
|
|
— |
Obrigatório. Método de quantização para o índice de baixa precisão. Valores aceitos: |
|
|
64 |
Número máximo de vizinhos aos quais cada vértice se conecta durante a construção do índice. Um valor maior melhora a precisão da busca, mas aumenta o tempo de construção do grafo e o armazenamento. Não exceda 96. |
|
|
400 |
Tamanho da lista de candidatos durante a construção do índice. Um valor maior melhora a precisão do índice, mas aumenta o tempo de construção. Não exceda 600. |
|
|
|
Define se deve ativar a camada de índice de alta precisão para reclassificação. |
|
|
|
Método de quantização para o índice de alta precisão. Efetivo apenas quando |
|
|
|
Meio de armazenamento para o índice híbrido. Efetivo apenas quando |
|
|
|
Controla a compressão do índice de grafo na memória. Valores aceitos: |
|
|
— |
Anexa valores de colunas ao índice para recuperação sem consultar a tabela vetorial. Tipos de coluna aceitos: |
|
|
4 |
Número de threads para construir o índice durante gravações. Não modifique na maioria dos cenários, pois aumentar este valor pode causar alta utilização da CPU. Modificar este parâmetro não aciona a reconstrução do índice. |
Modifique um índice
ALTER TABLE <TABLE_NAME>
SET (
vectors = '{
"<VECTOR_COLUMN_NAME>": {
"algorithm": "<ALGORITHM>",
"distance_method": "<DISTANCE_METHOD>",
"builder_params": {
"<BUILDER_PARAMETERS_NAME>": <VALUE>
[, ...]
}
}
}'
);
Exclua um índice
-- 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": { ... }
}'
);
Visualize um índice
Consulte a tabela de sistema hologres.hg_table_properties para visualizar os índices vetoriais criados.
SELECT
*
FROM
hologres.hg_table_properties
WHERE
table_name = '<TABLE_NAME>'
AND property_key = 'vectors';
Execute consultas de busca vetorial
Recuperação aproximada vs. exata
O Hologres oferece suporte à recuperação vetorial aproximada e exata. Apenas funções de recuperação aproximada podem usar o índice vetorial para acelerar consultas. A função aproximada usada na consulta deve corresponder ao distance_method do índice e respeitar a ordem de classificação exigida. Caso contrário, o sistema não usará o índice.
Funções de distância vetorial
Função | Tipo de recuperação | Entrada | Retorno | Observações |
| Aproximada |
|
| Usa índice vetorial; deve corresponder a |
| Aproximada |
|
| Usa índice vetorial; deve corresponder a |
| Aproximada |
|
| Usa índice vetorial; deve corresponder a |
| Exata |
|
| Não usa índice vetorial Não usa índice vetorial Não usa índice vetorial |
| Exata |
|
| |
| Exata |
|
|
Funções de distância não aceitam parâmetros de entrada totalmente constantes.
Verifique se o índice está sendo usado
Execute EXPLAIN ou EXPLAIN ANALYZE na consulta para verificar se o plano de execução usa o índice vetorial. Se o plano contiver Vector Filter, o índice está ativo.
Consulta de exemplo:
SELECT
id,
approx_euclidean_distance(feature, '{0.1,0.2,0.3,0.4}') AS distance
FROM
feature_tb
ORDER BY
distance
LIMIT 40;
Plano de execução de exemplo (índice usado):
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
Exemplo de ponta a ponta
O exemplo a seguir cria uma tabela com um índice vetorial, importa dados usando recursos de Serverless Computing e executa consultas de recuperação aproximada e exata.
Passo 1: Criar a tabela
-- 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
}
}
}'
);
Passo 2: Importar dados
-- 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;
Passo 3: Executar recuperação aproximada
-- 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;
Como esta tabela usa"extra_columns": "id", a consulta recupera valores deiddiretamente do índice vetorial sem ler a coluna da tabela base. Verifique o campovector_index_extra_columns_usedna saída doEXPLAIN ANALYZEpara ver quantos arquivos de manifesto forneceram valores por meio deextra_columns.
Passo 4: Executar recuperação exata
-- 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;
Ajuste de desempenho
Quando usar um índice vetorial
Para pequenos volumes de dados — por exemplo, dezenas de milhares de registros — ou quando sua instância possui amplos recursos de computação, dispense o índice vetorial e use computação por força bruta (exata). Adicione um índice vetorial apenas quando a recuperação exata não atender aos requisitos de latência, throughput ou escalabilidade.
Lembre-se de que índices vetoriais são inerentemente aproximados:
A taxa de recall não atinge 100%.
Uma consulta com
LIMIT 1000pode retornar menos de 1.000 resultados.
Escolha um método de quantização
O parâmetro base_quantization_type controla o equilíbrio entre uso de memória, velocidade de consulta e precisão de recall. Os valores aceitos são: sq8, sq8_uniform, fp16, fp32 e rabitq. Tipos de quantização de maior precisão usam mais memória, mas oferecem maior precisão de recall; tipos de menor precisão usam menos memória e melhoram a velocidade da consulta às custas de alguma precisão.
Para cargas de trabalho sensíveis à latência com índices totalmente em memória, use sq8_uniform ou rabitq. Para grandes conjuntos de dados com índices híbridos de memória e disco, use rabitq. Ao usar rabitq, ativar use_reorder: true com precise_quantization_type: fp32 pode melhorar a precisão do recall.
Escolha uma configuração de índice para sua carga de trabalho
Para uma única tabela, coluna única e índice vetorial de 768 dimensões, use as configurações a seguir como ponto de partida.
|
Carga de trabalho |
Tipo de índice |
Quantização |
Máximo de linhas por shard |
|
Sensível à latência |
Totalmente em memória |
|
5 milhões |
|
Grande volume de dados ou insensível à latência |
Híbrido memória-disco |
|
30–50 milhões |
Para múltiplas colunas vetoriais na mesma tabela, reduza proporcionalmente os limites de linhas por shard. O tamanho da dimensão do vetor também afeta esses limites.
Exemplo de índice totalmente em memória
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
}
}
}'
);
Exemplo de índice híbrido memória-disco
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
}
}
}'
);
Ajuste a taxa de recall
Os seguintes parâmetros de índice alcançam uma taxa de recall padrão acima de 95% no conjunto de dados VectorDBBench:
base_quantization_type:rabitqousq8_uniformprecise_quantization_type:fp32max_degree: 64ef_construction: 400
No momento da consulta, o parâmetro Grand Unified Configuration (GUC) hg_vector_ef_search controla o tamanho da lista de candidatos durante a recuperação. O valor padrão é 80, o que equilibra precisão e uso de recursos.
Para elevar o recall acima de 99%, aumente hg_vector_ef_search mantendo os parâmetros de índice inalterados:
SET hg_vector_ef_search = 400;
Para alcançar um recall de 99,5%–99,7%, ajuste simultaneamente os parâmetros de construção do índice e o parâmetro de consulta. Isso aumenta a latência da consulta, o uso de recursos da consulta, o tempo de construção do índice e o uso de recursos na construção do índice:
max_degree: 96ef_construction: 500 ou 600hg_vector_ef_search: 500 ou 600
Defina uma contagem adequada de shards
Mais shards geram mais arquivos de manifesto, o que reduz o throughput de consultas aproximadas. Siga estas diretrizes:
-
Dimensione os recursos de computação conforme seus dados. Para vetores de 768 dimensões: Para outras dimensões de vetores, consulte Especificações de instância para busca vetorial.
Índice totalmente em memória: até 5 milhões de vetores por worker.
Índice híbrido memória-disco: até 100 milhões de vetores por worker.
Defina a contagem de shards igual ao número de workers. Para uma instância de 64 CU, defina
shard_countcomo 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
}
}
}'
);
Consultas híbridas vetoriais e escalares
Para consultas que combinam recuperação vetorial com condições de filtro escalar, os padrões típicos são:
Filtrar por uma coluna de string (ex.: organização ou ID de grupo)
Um caso de uso comum é recuperar vetores dentro de um grupo específico — por exemplo, dados de reconhecimento facial de alunos em uma turma específica.
SELECT <distance_function>(feature, '{1,2,3,4}') AS d
FROM feature_tb
WHERE uuid = 'x'
ORDER BY d
LIMIT 10;
Otimize definindo:
uuidcomo chave de distribuição. Isso garante que todos os dados com o mesmo valor de filtro fiquem no mesmo shard, fazendo com que a consulta acesse apenas um shard.uuidcomo chave de clustering. Isso ordena os dados dentro dos arquivos poruuid, reduzindo o intervalo de varredura.
Filtrar por um campo de tempo
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;
Defina time_field como chave de segmento. Isso permite que o Hologres localize rapidamente os arquivos de dados relevantes pelo intervalo de tempo.
Estrutura de tabela recomendada para consultas híbridas
-- 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
}
}
}'
);
Reconstrua índices usando recursos Serverless
Algumas alterações de propriedades acionam compactação e reconstrução de índice, o que pode causar picos no uso da CPU. Trate essas alterações da seguinte forma:
Alterações em bitmap_columns, dictionary_encoding_columns ou índices vetoriais
Use a sintaxe REBUILD com recursos de Serverless Computing em vez de ALTER TABLE ... SET. Para mais informações, consulte 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
}
}
}'
);
Alterações no armazenamento colunar para dados JSON ou colunas de índice full-text
A sintaxe REBUILD ainda não é compatível com essas alterações. Use uma tabela temporária:
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;
Outras alterações de propriedades (ex.: distribution_key, clustering_key, segment_key, formato de armazenamento)
Use a sintaxe REBUILD com recursos de Serverless Computing.