<!-- Canonical: https://lucioduran.com/es/projects/vector-search-portability
Language: es
Content-SHA256: b40709d6a609b4aa100843c20be451e2ee1fc412570889a557343d8fc9a8aed6
-->

[Proyectos](<https://lucioduran.com/es/projects>) / Vector Search Portability

# Vector Search Portability

Comparación real de hnswlib y sqlite-vec con los mismos vectores, filtros y actualizaciones. Recall frente a búsqueda exacta, carga concurrente y pérdida por postfiltrado.

Autor: [Lucio Durán](<https://lucioduran.com/es>) · Python 3.11.13 · Licencia: [MIT](<https://github.com/lucioduran/vector-search-portability/blob/691a60ceecd4cb5eaaaf8570a073b80d96b9563e/LICENSE>)

Ficha publicada: 2026-10-21 · Ficha actualizada: 2026-10-21

[Repositorio](<https://github.com/lucioduran/vector-search-portability>) · [Evidencia original](<https://raw.githubusercontent.com/lucioduran/vector-search-portability/691a60ceecd4cb5eaaaf8570a073b80d96b9563e/results/reference/manifest.json>) · [Release v0.1.0](<https://github.com/lucioduran/vector-search-portability/releases/tag/v0.1.0>)

## Problema y utilidad para agentes

Migrar de motor puede conservar el número de resultados y cambiar cuáles son, cuánto cuestan los filtros o qué ocurre después de una actualización. El proyecto define un contrato común y mide esos desvíos.

Un agente que recupera contexto filtrado depende tanto de la semántica del filtro como del ranking. Esta comparación permite inspeccionar IDs, distancias, predicados y pérdida de candidatos antes de atribuir un fallo al modelo.

## Arquitectura

1. **Entrada congelada.** 5.000 vectores float32 de 64 dimensiones, 40 consultas y 500 actualizaciones de vector y metadatos. El NPZ publicado fija los bytes de entrada.
2. **Adaptadores nativos.** hnswlib 0.8.0 y sqlite-vec 0.1.6 comparten distancia L2 al cuadrado y filtros AND. Una búsqueda exhaustiva NumPy float64 actúa como referencia independiente.
3. **Procesos y trazas.** Tres repeticiones aisladas por motor alternan el orden de ejecución. Se registran búsqueda nativa y postfiltrado, carga de uno y cuatro clientes, CPU, RSS y snapshots.

- [Diseño y metodología](<https://github.com/lucioduran/vector-search-portability/blob/691a60ceecd4cb5eaaaf8570a073b80d96b9563e/docs/methodology.md>)

## Qué demuestra

- Contratos comparables entre motores con métricas y semántica de filtros explícitas.
- Evaluación de recall antes y después de cambios en vectores y metadatos.
- Análisis de costos del adaptador y preservación de mediciones originales y de confirmación.

## Resultados publicados

Resultados de referencia en Intel Xeon W-3223, macOS y Python 3.11.13. Las tablas de carga muestran medianas de tres ensayos, incluidos los percentiles de cada ensayo; no son percentiles agrupados.

Cada ensayo de carga realiza 400 búsquedas con filtros mezclados después de las actualizaciones. Recall@10 compara IDs con el top exacto. Pérdida de resultados mide cuántos faltan respecto de min(10, candidatos elegibles). El postfiltro parte de 40 vecinos globales.

### Carga de lectura del informe original

| Motor / clientes | Solicitudes/s | p50 (ms) | p95 (ms) |
| --- | --- | --- | --- |
| hnswlib / 1 | 1503.6 | 0.363 | 2.295 |
| hnswlib / 4 | 100.3 | 9.402 | 149.332 |
| sqlite-vec / 1 | 1412.7 | 0.666 | 0.801 |
| sqlite-vec / 4 | 2637.5 | 1.476 | 1.660 |

### Filtros después de actualizar, ambos motores

| Modo | Recall@10 | Pérdida de resultados |
| --- | --- | --- |
| Nativo, grupos no vacíos | 1.0000 | 0.0000 |
| Postfiltro por tenant | 0.4725 | 0.5275 |
| Postfiltro selectivo | 0.0275 | 0.9725 |

Ambos motores alcanzaron recall nativo 1,0 en esta muestra. El postfiltrado selectivo perdió el 97,25 % de los resultados disponibles aunque había 14 candidatos elegibles. Cuatro clientes degradaron el adaptador HNSW con predicado Python; el experimento no separa el costo del callback, el GIL y la máscara O(N).

La ejecución original conserva 9.600 búsquedas. Otra ejecución agrega 9.600 después de corregir la contabilidad de CPU, con la misma recuperación nativa y pérdida selectiva. Las cifras de la tabla siguen siendo las originales. [Resultados y análisis](<https://github.com/lucioduran/vector-search-portability/blob/691a60ceecd4cb5eaaaf8570a073b80d96b9563e/results/README.md>).

## Reproducir

Python 3.11, compilador C++ para hnswlib y SQLite con extensiones cargables. setup.py prepara las dependencias locales. No requiere modelos, servidor ni API.

Los comandos usan rutas POSIX. Algunos Python de macOS deshabilitan extensiones SQLite: el README documenta una instalación compatible. Conservá el NPZ fijado, elegí una salida nueva y evitá mediciones pesadas concurrentes.

### Revisar la evidencia guardada

```
git clone https://github.com/lucioduran/vector-search-portability.git
cd vector-search-portability
git checkout 691a60ceecd4cb5eaaaf8570a073b80d96b9563e
python3 scripts/setup.py
.venv/bin/python -m vector_portability verify --output results/reference
.venv/bin/python -m vector_portability verify --output results/confirmation
```

### Repetir la medición local

```
mkdir -p build
.venv/bin/python -m vector_portability run --output build/reproduced
.venv/bin/python -m vector_portability verify --output build/reproduced
```

## Alcance y límites

- Los vectores son sintéticos: se evalúan geometría y adaptadores, no relevancia lingüística ni escala de producción.
- Los motores tienen distinta durabilidad. La inserción de SQLite incluye commit; HNSW no garantiza persistencia ante caídas.
- Carga local de circuito cerrado sin red. RSS incluye intérprete y trazas; tres repeticiones sobre un equipo no establecen un ganador general.

- [Bases vectoriales: motores, filtros y decisiones de arquitectura](<https://lucioduran.com/es/blog/vector-databases-pgvector-qdrant-pinecone>)

## Fuentes y revisión

Las tablas resumen la ejecución de referencia del 21 de octubre de 2026. Los manifiestos enlazan los seis informes originales y los seis de confirmación con sus hashes. La revisión ejecutada indicada aquí corresponde a la referencia; el informe de confirmación identifica a416742cb7df20476b67c75dc4c13fe67c2d7ead.

- Revisión consultada: [` 691a60ceecd4cb5eaaaf8570a073b80d96b9563e `](<https://github.com/lucioduran/vector-search-portability/commit/691a60ceecd4cb5eaaaf8570a073b80d96b9563e>)
- Revisión registrada por el experimento: [` 7ee57a5af5e0f5bf4b46caf7eb55f0e1abd9fcf1 `](<https://github.com/lucioduran/vector-search-portability/commit/7ee57a5af5e0f5bf4b46caf7eb55f0e1abd9fcf1>)
- Fecha del informe (UTC): 2026-10-21
- Release publicada: [v0.1.0](<https://github.com/lucioduran/vector-search-portability/releases/tag/v0.1.0>) · 2026-10-21T22:16:31Z
- SHA-256 del corpus: ` 53fd9ca277d581075d2eb7df63348fbd52e92d4a0797b1e40454367ed3d409e0 `

- [README y uso](<https://github.com/lucioduran/vector-search-portability/blob/691a60ceecd4cb5eaaaf8570a073b80d96b9563e/README.md>)
- [Evidencia original](<https://raw.githubusercontent.com/lucioduran/vector-search-portability/691a60ceecd4cb5eaaaf8570a073b80d96b9563e/results/reference/manifest.json>)
- [Evidencia de confirmación](<https://raw.githubusercontent.com/lucioduran/vector-search-portability/691a60ceecd4cb5eaaaf8570a073b80d96b9563e/results/confirmation/manifest.json>)
- [Resultados y análisis](<https://github.com/lucioduran/vector-search-portability/blob/691a60ceecd4cb5eaaaf8570a073b80d96b9563e/results/README.md>)
- [Diseño y metodología](<https://github.com/lucioduran/vector-search-portability/blob/691a60ceecd4cb5eaaaf8570a073b80d96b9563e/docs/methodology.md>)
- [Corpus y procedencia](<https://github.com/lucioduran/vector-search-portability/blob/691a60ceecd4cb5eaaaf8570a073b80d96b9563e/data/fixed.npz>)
- [Dependencias del entorno medido](<https://github.com/lucioduran/vector-search-portability/blob/691a60ceecd4cb5eaaaf8570a073b80d96b9563e/requirements-local.lock>)
- [Licencia MIT](<https://github.com/lucioduran/vector-search-portability/blob/691a60ceecd4cb5eaaaf8570a073b80d96b9563e/LICENSE>)
