Vector Indexes no Oracle Database: Inverted File Flat (IVF) indexes – Parte 3
Chegamos à parte 3 dessa série de artigos sobre os Inverted File Flat indexes no Oracle Database, e agora o foco é entender como damos manutenção nesse tipo de índice. Se você ainda não leu os artigos anteriores, pode acessá-los aqui:
A precisão importa
Nos artigos anteriores, falei que os índices vetoriais fazem um trade-off entre velocidade e precisão. Para acelerar as consultas vetoriais nós perdemos precisão, mas precisamos ter uma precisão elevada o suficiente para que o modelo LLM que esteja consumindo a informação retornada não alucine, e retorne informacões de baixa qualidade. Bom, isso você já sabe, caso tenha acompanhado essa série de artigos.
O fato novo aqui é que podemos ter perda de precisão das nossas consultas, caso uma massa de dados seja inserida na tabela vetorial, e mude a distribuição dos dados, afetando o índice vetorial.
Para ilustrar, digamos que a nossa massa de dados tenha a seguintes distribuição:
Nesse exemplo, temos cidades, e cada cluster agrupa vetores baseados no estado dessas cidades. Agora, digamos que houve a inserção de novos dados. O seguinte ocorre:
Podemos observar que temos a partição #5 “inchada” (bloated). Isso acontece porque os vetores são inseridos na partição cujo centróide esteja mais próximo desses vetores. Com isso, as consultas top-K podem retornar resultados menos precisos, além de termos uma performance pior quando essas partições maiores precisam ser varridas.
Nesse caso, o ideal é realizar o rebuild do índice. Durante o rebuild, o Oracle irá recalcular a quantidade de centróides necessários para o novo espaço vetorial encontrado, e criar novas partições para comportar os dados. Levando para o nosso exemplo, este seria o espaço vetorial após o rebuild do índice, com duas novas partições existentes, com centróides próprios:
Mensurando a precisão
Agora que entendemos o problema, e temos a solução, a grande questão é: como podemos monitorar a precisão do nosso índice, para saber quando o rebuild se faz necessário?
Para essa monitoria, a versão 26ai do Oracle traz duas funções na package DBMS_VECTOR: INDEX_ACCURACY_QUERY e INDEX_ACCURACY_REPORT.
Aqui vou demonstrar o funcionamento delas, usando um notebook do Google Colab (disponível no meu GitHub). Iniciando pela INDEX_ACCURACY_QUERY, essa função necessita de um vetor para comparação, um valor para top-K e a precisão alvo. Para isso, gerei uma embedding utilizando a OpenAI e a armazenei numa variável vector_arr:

Na sequência, passo essa variável como bind para a função, no parâmetro qv (query vector). Além disso, é preciso especificar o owner e o índice que será avaliado, quantos valores mais próximos devem ser retornados (top_k) e a precisão alvo (target_accuracy), de 90% nesse caso:

O retorno dessa função é o texto: “Accuracy achieved (100%) is 10% higher than the Target Accuracy requested (90%)“. Por trás dos panos, o que o Oracle faz é executar uma Exact Search, para identificar qual seriam os resultados com 100% de precisão, e na sequência, executa a query novamente, utilizando a Approximate Search através do Inverted File Flat index, e compara os resultados da segunda query com a primeira, calculando assim a precisão.
Essa função é interessante para testes pontuais, para análise da precisão para perguntas específicas feitas à LLM. Agora para um monitoramento contínuo, o ideal é utilizar o INDEX_ACCURACY_REPORT. Essa função recebe o owner e o nome do índice, além dos parâmetros start_time e end_time, para especificar uma janela de tempo na qual a análise deseja ser feita. Se estes dois não forem especificados, a análise será feita com base nas informações das últimas 24 horas.

O retorno aqui é um número (neste caso 5), que representa a task_id executada. Com esse valor, podemos consultas os resultados da análise na view DBA_VECTOR_INDEX_ACCURACY_REPORT.
SELECT MIN_TARGET_ACCURACY, MAX_TARGET_ACCURACY, NUM_VECTORS, MIN_ACHIEVED_ACCURACY, MEDIAN_ACHIEVED_ACCURACY, MAX_ACHIEVED_ACCURACY
FROM DBA_VECTOR_INDEX_ACCURACY_REPORT WHERE task_id = 5;
MIN_TARGET_ACCURACY MAX_TARGET_ACCURACY NUM_VECTORS MIN_ACHIEVED_ACCURACY MEDIAN_ACHIEVED_ACCURACY MAX_ACHIEVED_ACCURACY
------------------- ------------------- ----------- --------------------- ------------------------ ---------------------
1 10 2 49 57 65
11 20 3 60 73 83
21 30 3 44 64 84
31 40 2 63 76.5 90
41 50 3 63 81 90
61 70 2 57 68 79
71 80 3 79 87 89
81 90 3 70 71 78
91 100 4 67 79.5 88
Na saída acima, cada linha representar um bucket para as precisões alvo (aquelas definidas na Approximate Search). O exemplo acima eu retirei da documentação, uma vez que no meu ambiente de testes a view estava vazia, provavelmente pelo baixo volume de queries executadas no período de análise.
O ideal aqui é que MIN_ACHIEVED_ACCURACY, MEDIAN_ACHIEVED_ACCURACY e MAX_ACHIEVED_ACCURACY, que representam as precisões mínimas, mediana e máximas alcançadas em cada bucket. Se o valor estiver muito abaixo do esperado, e uma carga recente tenha sido feita na tabela vetorial indexada, isso pode indicar que o índice perdeu a precisão, como exemplificado no ínicio do artigo.
Conclusão
Diferente de índices convencionais, os índices vetoriais necessitam desse acompanhamento mais próximo, pois uma vez que a precisão é comprometida, também será a qualidade das respostas dadas pela LLM. Se pensarmos em um bot de atendimento ao cliente, ou semelhante, um índice com baixa precisão pode afetar a qualidade das respostas, e com isso a satisfação de quem está usando a ferramenta.
Vale citar aqui que a necessidade desse acompanhamento depende muito do comportamento da tabela vetorial. Se os dados que serão inseridos nela são uma base finita de dados e que não sofrerá cargas futuras, você pode checar a precisão de uma maneira menos constante do que em tabelas onde a base de conhecimento cresce ou se modifica constantemente. Em cenários mais dinâmicos, os rebuilds de Inverted File Flat indexes podem ser mais frequentes.



Publicar comentário