Una consulta al directorio.
Un escaneo contiguo.
La búsqueda vectorial filtrada suele ser un scatter-gather sobre un índice que no sabe nada de tu filtro. Telys controla la disposición física en su lugar: sobre la clave de partición, nearest-neighbours-where-key-equals-x es una consulta O(1) al directorio más un escaneo secuencial de un bloque contiguo. Esta página recorre el runtime que se entrega hoy y la arquitectura hacia la que converge — etiquetada como spec.
El motor controla dónde vive cada vector.
Una colección declara partition_by en su creación, y la disposición sigue la clave. El segmento base está agrupado por partición — cada clave se asigna a un único bloque contiguo — y las escrituras recientes residen junto a él en un delta mutable con forma Arrow.
Agrupado por partición
Vectores almacenados ordenados por clave de partición, de modo que cada partición es un bloque contiguo. Una consulta con scope lee una única secuencia de memoria, no filas dispersas por un índice.
O(1) clave → slice
Un directorio asigna cada valor de partición a su (offset, length) en el segmento base. Resolver el filtro es una búsqueda en diccionario, no un recorrido de índice.
Escrituras con forma Arrow
add y upsert se añaden aquí; cada fila lleva un LSN de escritura monotónico. El delta es consultable de inmediato y se une al slice base a través de un único camino de escaneo.
Lo que ejecuta una consulta con scope.
col.search(qvec, where={"tenant_id": "acme"}, top_k=10)
El filtro nombra la clave de partición con la que se creó la colección.
Búsqueda O(1): el valor de partición se resuelve a (offset, length) en el segmento base. Sin generación de candidatos, sin punto de entrada en el grafo.
Puntuación exacta SIMD sobre un bloque secuencial. El recall en este camino es 1.0 — es un escaneo, no una aproximación. Los valores p50/p95 medidos para este paso se publican en la página de benchmarks, cada uno vinculado a su umbral de recall y equipo.
Las filas con la misma clave en el delta con forma de Arrow se puntúan por el mismo camino. Una escritura es visible para la siguiente consulta inmediata.
Los hits se filtran en el LSN de snapshot: las versiones con tombstone o supersedidas nunca emergen. Top-k retorna con el payload de explain adjunto.
Las particiones sobredimensionadas toman un fork declarado: build_ivf coloca un IVF por partición sobre cualquier partición que supere el umbral de filas, y las consultas se enrutan a través de él con un rerank exacto — calibrado contra un recall floor, y nombrado en el plan.
Cada resultado nombra su plan.
explain=True devuelve el plan físico que tomó la consulta. Con la clave de partición se obtiene el escaneo de slice contiguo. Las particiones sobredimensionadas declaran el fork IVF. Los filtros fuera de clave recurren al scatter-gather — y el payload explica por qué.
hits = col.search(qvec, where={"tenant_id": "acme"}, top_k=10, explain=True)
hits["explain"]["plan"]
# on the partition key → "PartitionSliceExactF32" # one contiguous slice, exact, recall 1.0
# oversized partition → "PartitionIVFRerankF32" # per-partition IVF + exact rerank
# off-key filter → "ScatterGatherExact" # fallback — and it says why:
hits["explain"]["fallback_reason"]
# "path is not the physical partition key"Nada se sobreescribe. Las versiones se superseden.
El modelo de escritura es MVCC append-only. upsert escribe una nueva versión de un id lógico y marca la anterior como supersedida; delete coloca un tombstone en un LSN de borrado; snapshot() fija una vista de lectura consistente; compact() fusiona el delta en la base y descarta lo que ningún snapshot puede ver.
col.upsert(vectors, ids=ids, metadata=metadata) # a new version; the prior one is superseded col.delete(["doc-41"]) # tombstone at a delete LSN — no in-place erase lsn = col.snapshot() # pin a consistent read view at an LSN col.compact() # fold delta into base; drop superseded rows col.build_ivf(min_rows=20000, target_recall=0.98)
| Llamada | Qué hace |
|---|---|
| agregar / agregar_textos | Inserta nuevas filas. Los ids duplicados se rechazan — una segunda fila física para un id lógico requiere upsert, de forma deliberada. |
| upsert / upsert_textos | Escribe una nueva versión de un id lógico; la versión anterior queda supersedida, nunca sobreescrita en su lugar. |
| buscar / buscar_texto | Top-k filtrado. explain=True adjunta el plan físico al resultado. |
| delete | Marca con tombstone filas lógicas en un LSN de borrado. |
| compact | Fusiona el delta en el segmento base; descarta versiones con tombstone o supersedidas. |
| build_ivf | Construye IVF por partición sobre las particiones que superan el umbral de filas, calibrado a un recall floor. |
| snapshot | Devuelve un LSN que fija una vista de lectura consistente. |
| save / stats | Persiste la colección en disco; reporta conteos de filas, particiones y datos de layout. |
Todo lo que sigue es especificación, no referencia de API publicada. Es el sustrato al que converge el runtime. La interfaz orientada al SDK está congelada, por lo que el cambio subyacente es invisible para los llamadores.
Un planner. Una IR plana. Un executor.
Tres front ends convergen en un planner, que emite una representación intermedia física plana, ejecutada por un executor vectorizado Mojo directamente sobre buffers Arrow.
El modelo de memoria (remember · recall · as_of), la API de consulta (point_get · scan · search · hybrid_search) y el fabric. Un contrato de entrada; ningún motor por API.
Planificación lógica y física en un único lugar. La selectividad se estima a partir de estadísticas de segmento; el plan es explícito y se devuelve con el resultado.
Un array plano de operadores enlazados por slots enteros. El registro inter-operador es un row set — un bitmap, row-ids ordenados o un selection vector.
Ejecución vectorizada sobre buffers Arrow y arrays de candidatos FAISS. El hot path SIMD permanece fuera de Python; las páginas Parquet comprimidas se decodifican primero en scratch buffers.
La capa de mutación
Un write-ahead log para durabilidad y ordenación, y un delta mutable con forma de Arrow para visibilidad inmediata — la capa de tabla que Parquet no ofrece por sí solo.
Sellados, inmutables
Segmentos columnares comprimidos y duraderos. Las estadísticas del footer guían la poda de segmentos y row-groups; los archivos sellados nunca se mutan.
FAISS ANN
Índices FAISS por segmento, vinculados al checksum y versión del segmento, mapeados en solo lectura con tiempo de vida ligado al snapshot de lectura.
Poda y léxico
Zone maps, bloom filters y bitmaps para poda; un sidecar BM25 para recuperación dispersa y fusión de puntuaciones.
SCAN FILTER PROJECT POINT_GET RANGE_GET AGGREGATE TOP_K HASH_JOIN HASH_GROUP_BY SORT ANN_SEARCH SPARSE_SEARCH FUSE RERANK MATERIALIZE
WAL primero. Visible de inmediato. Sellado en segundo plano.
Frames append-only con checksums y LSNs monotónicos. La recuperación reproduce registros a partir del último LSN sellado y trunca en el primer checksum inválido.
La escritura aterriza en el delta mutable y es consultable de inmediato — los segmentos sellados y el delta se unen a través de un único camino de escaneo.
Superado un umbral de tamaño, filas o antigüedad, el delta se ordena y se escribe como segmento Parquet con su .vidx y sidecars, y se publica mediante un intercambio atómico de manifiesto.
Las fusiones en segundo plano consolidan segmentos pequeños, eliminan filas con tombstone y reconstruyen los sidecars — con presupuesto controlado, para que los despliegues en dispositivo permanezcan silenciosos.
Los segmentos sellados nunca se mutan. Una lectura ancla (snapshot de manifiesto, LSN); los escritores sellan nuevos segmentos e intercambian el manifiesto sin perturbar a los lectores en vuelo. La recolección de basura espera al snapshot activo más antiguo.
El filtro elige el plan, no al revés.
El ANN filtrado es planificación adaptativa por selectividad: el planificador estima cuántas filas sobreviven al filtro a partir de las estadísticas de segmento y elige la estrategia más económica que mantiene el contrato de recall.
Prefiltro → exacto
Prefiltro escalar o de bitmap primero, luego puntuación SIMD exacta sobre los supervivientes. Por debajo de un umbral de filas, el ANN se omite por completo — escaneo exacto, recall 1.0.
Recorrido con allow-bitmap
El recorrido ANN lleva un allow-bitmap, de modo que el índice solo expone las filas que el filtro admite.
ANN → postfiltro
ANN primero con sobre-obtención adaptativa, luego postfiltro. El filtro elimina poco, por lo que la generación de candidatos lidera.
Las verificaciones de corrección preceden a cualquier cifra de rendimiento.
El runtime publicado se verifica mediante suites de paridad ejecutadas contra ambas implementaciones del motor, y cada consulta puede nombrar el plan físico que tomó. Este es el orden de operaciones aquí: corrección primero, medición después.
Los benchmarks se publican bajo un contrato de equidad — recall equiparado, hardware equiparado, resultados separados por transporte, victoria / empate / derrota reportados. Los primeros resultados medidos están disponibles en la página de benchmarks, cada cifra acompañada de sus condiciones completas: hardware, conjunto de datos, dimensión, selectividad, recall y transporte. Todo multiplicador sigue siendo una hipótesis fuera de las condiciones declaradas junto a él.