Azure Managed Redis: búsqueda vectorial, HNSW, FLAT, Hash y JSON
Volver a la ruta AI-200
AI-200Capítulo 17

Preparación para la Certificación Microsoft AI-200

Azure Managed Redis: búsqueda vectorial, HNSW, FLAT, Hash y JSON

Diseña recuperación semántica de baja latencia con dimensiones exactas, métricas adecuadas, consultas KNN y de rango, filtros de metadatos, ajuste medible de HNSW y una elección consciente entre Hash y JSON.

Tiempo de estudio sugerido: 120 minutos • Nivel intermedio • Reescritura original completa con versión resumida de cada tema, evaluación comentada y laboratorio guiado en Python

Escudo neón Microsoft Certified AI-200 con búsqueda vectorial en Azure Managed Redis, embeddings, grafo HNSW, índice FLAT, Hash y JSON

1. El problema de recuperación semántica y los objetivos

Un asistente empresarial puede guardar millones de documentos técnicos y aun así debe responder en milisegundos. Las palabras clave no capturan toda la intención; por eso, la aplicación convierte documentos y preguntas en embeddings de alta dimensión. Los conceptos relacionados quedan cerca en el espacio vectorial, lo que habilita búsqueda semántica, recomendaciones y RAG.

La solución también debe conservar dimensión y tipo numérico, almacenar consultables, elegir indexación exacta o aproximada, actualizar registros, filtrar por autorización o departamento y medir latencia, recall, memoria y costo. El ejemplo usa 1.536 dimensiones sin asumir que todos los modelos tengan ese tamaño.

  • Crear esquemas vectoriales de RediSearch e ingerir embeddings con redis-py.
  • Ejecutar consultas KNN, de rango e híbridas con .
  • Elegir FLOAT32 o FLOAT64, métrica de distancia y FLAT o HNSW a partir de mediciones.
  • Seleccionar Redis o Redis y planear migraciones y reindexaciones seguras.
  • Construir y validar una aplicación Python de búsqueda semántica en .

Resumen del tema

La recuperación vectorial es un contrato completo: modelo, esquema, , índice, parámetros y métricas operativas deben coincidir.

2. Aprovisiona para búsqueda vectorial

ofrece capacidades vectoriales mediante el módulo administrado RediSearch. Debe habilitarse al crear la instancia porque no se pueden agregar módulos después. La configuración actual también requiere la directiva de clustering Enterprise, NoEviction y un nivel en memoria compatible: Memory Optimized, Balanced o Compute Optimized. Flash Optimized no admite RediSearch.

Dimensiona registros y sobrecarga del índice secundario. Usa ; prefiere autenticación de cuando el cliente la admita; y evalúa Private Link, alta disponibilidad, diagnósticos y recuperación. administra las versiones de módulos, por lo que conviene probar la versión del servicio y no suponer un módulo instalado manualmente.

Decisiones que no se pueden posponer
DecisiónValidación
MóduloRediSearch habilitado durante la creación
ClusteringDirectiva Enterprise
EvicciónNoEviction para proteger los datos indexados
NivelMemory Optimized, Balanced o Compute Optimized
CapacidadVectores, , índice, réplicas y crecimiento
Seguridad, identidad o claves, aislamiento de red y diagnósticos

Resumen del tema

La búsqueda vectorial empieza en el aprovisionamiento: RediSearch, clustering Enterprise, NoEviction, nivel compatible y memoria suficiente son requisitos previos.

3. Del contenido a los resultados indexados

La aplicación divide el contenido en unidades recuperables, crea un embedding por unidad y guarda vector, identidad, origen, categoría, fecha, inquilino y control de acceso. RediSearch observa las claves del prefijo e incrementa su índice secundario. La pregunta pasa por el mismo modelo y preprocesamiento antes de KNN o VECTOR_RANGE.

Los restringen candidatos y aportan trazabilidad. En RAG, la aplicación recupera texto y procedencia, construye contexto fundamentado y lo entrega al modelo generativo. La distancia clasifica candidatos; no autoriza acceso ni garantiza la verdad de una afirmación.

Flujo desde documentos y embeddings hasta resultados semánticos filtrados en RediSearch
Diagrama original: contenido y se almacenan juntos; la pregunta usa el mismo modelo antes de la recuperación filtrada.

Resumen del tema

Usa el mismo contrato de embeddings al indexar y consultar, guarda procedencia y acceso con el vector y trata la recuperación como ranking, no como autorización.

4. Define un índice vectorial sobre Redis

El esquema de RediSearch declara campos consultables y retornables. El campo vectorial define algoritmo, TYPE, DIM y DISTANCE_METRIC; texto y etiquetas habilitan filtros híbridos. IndexDefinition limita la indexación a un prefijo y especifica si la fuente es o .

from redis.commands.search.field import TagField, TextField, VectorField
from redis.commands.search.indexDefinition import IndexDefinition, IndexType

schema = (
    TextField("title"),
    TagField("department"),
    VectorField("embedding", "HNSW", {
        "TYPE": "FLOAT32",
        "DIM": 1536,
        "DISTANCE_METRIC": "COSINE",
        "M": 16,
        "EF_CONSTRUCTION": 200,
    }),
)

client.ft("idx:documents").create_index(
    schema,
    definition=IndexDefinition(
        prefix=["doc:"],
        index_type=IndexType.HASH,
    ),
)

El ejemplo usa HNSW, FLOAT32, 1.536 dimensiones y distancia coseno. M y EF_CONSTRUCTION afectan conectividad, memoria, tiempo de construcción y recall. El prefijo doc: excluye claves ajenas. La creación del esquema debe ser una fase de implementación versionada con reversión, no una acción implícita en cada inicio.

Resumen del tema

El índice debe unir algoritmo, tipo, dimensión, métrica, , tipo de fuente y prefijo en un esquema estable.

5. Almacena vectores y correctamente

Los vectores en se guardan como blobs binarios compactos. Convierte la salida al dtype exacto, valida su forma unidimensional y luego usa tobytes(). Los campos humanos siguen siendo normales. Un embedding FLOAT32 de 1.536 valores ocupa 6.144 bytes antes de objetos Redis, , replicación e índice.

import numpy as np

embedding = np.asarray(model_embedding, dtype=np.float32)
if embedding.shape != (1536,):
    raise ValueError("The embedding must contain exactly 1536 values")

client.hset("doc:917", mapping={
    "title": "Model deployment runbook",
    "department": "engineering",
    "content": "Operational steps for model deployment...",
    "embedding": embedding.tobytes(),
})

Diferencias de dimensión o dtype pueden invalidar el índice o la consulta. No recortes, rellenes ni reinterpretes vectores silenciosamente. Guarda modelo y versión en los ; una migración de modelo suele requerir otro campo o índice hasta completar el cambio.

Resumen del tema

En , serializa el dtype exacto, valida DIM, conserva útiles y versiona el contrato de embeddings.

6. Ingesta por lotes, actualizaciones y visibilidad

Una ida a la red por documento es costosa. El de redis-py agrupa comandos; transaction=False deja claro que se optimizan viajes y no se crea una transacción total. Usa lotes limitados para no presionar la memoria, las colas ni los reintentos.

with client.pipeline(transaction=False) as pipe:
    for document in documents:
        vector = np.asarray(document["embedding"], dtype=np.float32)
        pipe.hset(f'doc:{document["id"]}', mapping={
            "title": document["title"],
            "department": document["department"],
            "content": document["content"],
            "embedding": vector.tobytes(),
        })
    responses = pipe.execute()

# Batching reduces network round trips; it does not make the whole load atomic.
assert all(result >= 0 for result in responses)

RediSearch mantiene el índice cuando cambian las claves. Tras una carga, verifica recuentos y consultas reales. Claves deterministas hacen idempotentes los reintentos. Registra fallos de execute(), aplica espera y observa las transiciones del modelo. La mejora depende de red, carga y ; mídela.

Resumen del tema

Los reducen viajes, las claves deterministas protegen los reintentos y las verificaciones posteriores prueban que el índice está listo.

7. Ejecuta una consulta KNN

KNN solicita una cantidad fija de vecinos. La sintaxis indica K, campo, parámetro binario y alias de distancia. Devuelve solo lo necesario y ordena por distancia. Las consultas vectoriales usan dialecto 2; redis-py reciente ya lo solicita, pero declararlo hace el ejemplo explícito.

from redis.commands.search.query import Query

query_vector = np.asarray(query_embedding, dtype=np.float32).tobytes()
query = (
    Query("*=>[KNN 5 @embedding $query_vec AS vector_distance]")
    .return_fields("title", "department", "vector_distance")
    .sort_by("vector_distance")
    .dialect(2)
)

results = client.ft("idx:documents").search(
    query,
    query_params={"query_vec": query_vector},
)

Con COSINE, una distancia menor indica mayor cercanía: cero representa la misma dirección y el valor puede acercarse a dos para direcciones opuestas. No es una probabilidad universal. Calibra límites con ejemplos etiquetados del modelo, idioma, dominio y fragmentación reales.

Resumen del tema

KNN devuelve los K más cercanos; envía el vector como bytes, ordena por el alias e interpreta la distancia solo dentro de una carga calibrada.

8. Combina similitud con filtros de

La búsqueda híbrida restringe candidatos por y los clasifica por distancia. Puede limitar por producto, departamento, inquilino o clasificación permitida. Los filtros forman parte de la corrección y seguridad, no son solo optimización.

query = (
    Query(
        "@department:{engineering}=>"
        "[KNN 3 @embedding $query_vec AS vector_distance]"
    )
    .return_fields("title", "department", "vector_distance")
    .sort_by("vector_distance")
    .dialect(2)
)

Las etiquetas con caracteres reservados deben escaparse o modelarse con cuidado. Aplica todos los predicados obligatorios en el servidor y vuelve a validar los resultados. Mide selectividad: un filtro restrictivo puede acelerar la comparación, pero datos sesgados o un índice inadecuado cambian la latencia.

Resumen del tema

Las consultas híbridas combinan restricciones obligatorias y ranking; los filtros deben indexarse, escaparse y aplicarse dentro del límite de autorización.

9. Usa VECTOR_RANGE para umbrales

KNN intenta devolver K candidatos incluso si son malos. VECTOR_RANGE devuelve todos los registros dentro de una distancia máxima y puede devolver cero. Es útil para caché semántica, duplicados y RAG que debe abstenerse si no existe una fuente suficientemente cercana.

query = (
    Query(
        "@embedding:[VECTOR_RANGE $radius $query_vec]"
        "=>{$YIELD_DISTANCE_AS: vector_distance}"
    )
    .return_fields("title", "vector_distance")
    .sort_by("vector_distance")
    .dialect(2)
)

results = client.ft("idx:documents").search(
    query,
    query_params={"radius": 0.20, "query_vec": query_vector},
)

Define el radio con datos de evaluación. Un mismo número cambia entre COSINE, L2, y modelos. En HNSW, EPSILON amplía la exploración de una consulta de rango y puede mejorar recall con mayor tiempo.

Resumen del tema

Usa KNN para K candidatos ordenados y VECTOR_RANGE cuando solo deben aceptarse elementos dentro de un límite calibrado.

10. Haz coincidir tipo numérico y dimensiones

Representaciones comunes
PropiedadFLOAT32FLOAT64
Bytes por dimensión48
de 1.536 dimensiones6.144 bytes (~6 KiB)12.288 bytes (~12 KiB)
Precisión típicaAproximadamente 7 dígitosAproximadamente 15 dígitos
Uso habitualMayoría de embeddings de IACaso especializado que demuestre necesidad

FLOAT32 es el valor predeterminado normal y reduce el frente a FLOAT64. Redis moderno puede ofrecer tipos cuantificados adicionales, pero controla la versión del módulo; confirma compatibilidad y recall. El módulo de origen se concentra en FLOAT32 y FLOAT64.

DIM viene del modelo: 384, 768, 1.024, 1.536 y 3.072 son ejemplos, no opciones intercambiables. Índice, registro y consulta deben tener exactamente el mismo número de elementos y tipo. Cambiar de modelo exige re-embedding y reindexación.

Resumen del tema

FLOAT32 es el estándar habitual; DIM y dtype deben coincidir exactamente en modelo, bytes, esquema y consulta.

11. Elige COSINE, L2 o producto interno

Métricas de distancia
MétricaQué midePunto de partida
COSINEÁngulo; ignora en gran parte la magnitudTexto y modelos entrenados para coseno
L2Distancia euclidiana; importa dirección y magnitudImágenes o espacio si el modelo especifica L2
Producto internoVectores normalizados o ranking diseñado para dot product

El contrato del modelo y la evaluación determinan la métrica. Una opción matemáticamente válida puede ordenar mal si el modelo fue entrenado para otra comparación. Normaliza solo cuando lo exijan modelo y métrica.

Resumen del tema

Elige la métrica esperada por el modelo y valida la recuperación con consultas etiquetadas y representativas.

12. FLAT exacto frente a HNSW aproximado

FLAT compara la consulta con todos los vectores y ofrece búsqueda exhaustiva. Es simple y exacto, pero crece linealmente. HNSW crea un grafo navegable por capas y visita nodos prometedores. Suele reducir la latencia a escala, aceptando que puede omitir un vecino verdadero.

Comparación de escaneo FLAT exhaustivo y navegación del grafo HNSW
Diagrama original: FLAT examina candidatos; HNSW atraviesa una jerarquía hacia la región cercana.
Elección del índice
NecesidadInicioRazón
Conjunto pequeño, baseline o exactitud exhaustivaFLATEscaneo exacto y referencia de recall
Conjunto grande con objetivo de latenciaHNSWEl grafo aproximado escala mejor
Embeddings de textoFLOAT32 + COSINE y mediciónContrato común, no regla
Embeddings de imagenFLOAT32 + métrica del modeloL2 es común, pero decide el modelo

Umbrales como diez mil o un millón de registros son heurísticas. Dimensión, nivel, selectividad, concurrencia, recall y memoria desplazan el cruce. Usa FLAT como verdad de referencia al medir recall de HNSW.

Resumen del tema

FLAT es exhaustivo; HNSW cambia parte del recall por latencia escalable. Elige con benchmarks, no con una cifra fija.

13. Ajusta y evalúa HNSW

M aumenta conexiones y suele mejorar navegación con más memoria. EF_CONSTRUCTION amplía vecinos durante la construcción y eleva tiempo y normalmente recall. EF_RUNTIME controla candidatos por consulta: subirlo tiende a mejorar recall y latencia. Los valores predeterminados solo son puntos de partida.

query = Query(
    "*=>[KNN 10 @embedding $query_vec EF_RUNTIME $ef AS vector_distance]"
).sort_by("vector_distance").dialect(2)

for ef_runtime in (10, 50, 100, 200):
    started = time.perf_counter()
    result = client.ft("idx:documents").search(
        query,
        query_params={
            "query_vec": query_vector,
            "ef": ef_runtime,
        },
    )
    latency_ms = (time.perf_counter() - started) * 1000
    evaluate(ef_runtime, latency_ms, result.docs)

Crea un conjunto etiquetado y mide p50, p95, p99, throughput, memoria, construcción y recall@K frente a FLAT. Prueba concurrencia y filtros reales. Elige la configuración de menor costo que cumpla el objetivo y repite tras cambios de modelo, datos, nivel o tráfico.

Resumen del tema

Ajusta M y EF_CONSTRUCTION al construir y EF_RUNTIME al consultar; compara con FLAT y mide cola de latencia, rendimiento y memoria.

14. Modela vectores en o Redis

representa un registro plano y guarda el vector como bytes compactos; es un buen estándar si el esquema es simple. Redis conserva objetos y matrices anidados; el vector se guarda como matriz numérica, aunque la consulta se pasa en bytes. JSONPath y alias simplifican el esquema.

from redis.commands.json.path import Path

document = {
    "name": "Wireless headset",
    "price": 99.90,
    "category": "electronics",
    "specs": {"color": "black", "wireless": True},
    "embedding": embedding.tolist(),
}
client.json().set("jdoc:12345", Path.root_path(), document)

schema = (
    TextField("$.name", as_name="name"),
    TagField("$.category", as_name="category"),
    VectorField("$.embedding", "HNSW", {
        "TYPE": "FLOAT32", "DIM": 1536,
        "DISTANCE_METRIC": "COSINE",
    }, as_name="embedding"),
)
Flujo de decisión entre Redis Hash y Redis JSON para vectores
Diagrama original: para registros planos y compactos; Redis para documentos anidados o cambiantes.
Comparación y
FactorRedis
VectorBytes binariosMatriz numérica
FormaCampos planosObjetos y matrices anidados
RutasNombres de campoJSONPath con alias
Mejor inicioRegistros compactosDocumentos complejos o ya
DecisiónMedir memoria y latenciaMedir flexibilidad y sobrecarga

Resumen del tema

Elige para registros planos compactos y para documentos anidados; fuente, representación e IndexDefinition deben coincidir.

15. Migra estructuras y versiones de índice con seguridad

Convertir a cambia el tipo de clave y el índice. Una migración segura escribe bajo otro prefijo, crea un índice , valida recuentos y consultas, cambia lectores deliberadamente y conserva el origen para reversión. Sobrescribir la misma clave no es una estrategia.

# Write transformed documents under a new prefix; do not overwrite Hash keys.
for key in client.scan_iter(match="product:*"):
    source = client.hgetall(key)
    vector = np.frombuffer(source[b"embedding"], dtype=np.float32)
    target = {
        "name": source[b"name"].decode(),
        "price": float(source[b"price"]),
        "category": source[b"category"].decode(),
        "embedding": vector.tolist(),
    }
    client.json().set(f"j{key.decode()}", Path.root_path(), target)

# Build and validate the JSON index, then switch reads deliberately.
# Keep the old index until validation and rollback windows are complete.

El mismo método azul-verde sirve para cambiar el modelo: nuevo campo o prefijo, índice versionado, backfill, comparación, corte y retirada posterior. Supervisa fallos, memoria, escrituras rechazadas, latencia y recall.

Resumen del tema

Usa prefijos nuevos e índices versionados, valida antes del corte y conserva reversión hasta demostrar el nuevo camino.

16. Laboratorio guiado: implementa búsqueda semántica

El ejercicio crea un recurso compatible con Enterprise, descarga archivos iniciales, completa la lógica Python, carga vectores, guarda , recupera por clave, calcula similitud coseno y busca productos relacionados. Reserva unos 40 minutos después de preparar el entorno.

Requisitos previos

  • Suscripción de con permiso para crear el nivel y configuración necesarios de .
  • , Python 3.12 o posterior, CLI de actual y extensión redisenterprise.
  • Instancia con RediSearch, clustering Enterprise, NoEviction, y capacidad suficiente.
  • Datos iniciales con modelo, dimensiones, dtype y métrica documentados.
az extension add --name redisenterprise
az redisenterprise show   --resource-group <resource-group>   --cluster-name <cache-name>

python -m venv .venv
# Activate the virtual environment for your shell.
python -m pip install --upgrade redis numpy azure-identity
python app.py
  1. Conecta de forma segura y confirma PING.
  2. Crea un índice versionado y verifica el esquema.
  3. Carga muestras en limitados y comprueba recuentos.
  4. Implementa lectura por clave y coseno independiente para pruebas.
  5. Ejecuta KNN, KNN filtrado y VECTOR_RANGE con ejemplos conocidos.
  6. Compara FLAT y HNSW en latencia y recall y documenta parámetros.
  7. Elimina el recurso de laboratorio si ya no es necesario.

Resumen del tema

El laboratorio demuestra el ciclo completo: recurso seguro, esquema, ingesta, lectura, cálculo, consultas y selección medida del índice.

17. Revisión de evaluación y lista de producción

Respuestas esenciales
PreguntaRespuestaRazón
Métrica típica para textoCOSINEContrato común para dirección semántica
Gran conjunto y rapidez con aproximación aceptableHNSWBúsqueda aproximada por grafo
Tipo usual para embeddingsFLOAT32Precisión suficiente con menos memoria
Registros planos y máxima eficienciaVector binario compacto
Qué cambia EF_RUNTIMEEquilibrio velocidad-recallCandidatos explorados en HNSW

En producción, confirma módulo y nivel, contrato del modelo, filtros obligatorios, prefijos, versiones, margen de memoria, , identidad, red, ingesta limitada, reintentos idempotentes, paneles, alertas, pruebas de relevancia y reversión. Ninguna cifra aislada sustituye pruebas con vectores y tráfico reales.

  1. Microsoft Learn: embeddings y búsqueda vectorial en
  2. Microsoft Learn: documentación de
  3. Redis: conceptos y parámetros de búsqueda vectorial
  4. Redis: indexar y consultar vectores con redis-py
  5. Microsoft Learn: referencia de az redisenterprise

Resumen del tema

Recuerda el contrato: COSINE es común para texto, FLOAT32 es el estándar, HNSW es la opción aproximada escalable, sirve para datos planos y toda decisión debe medirse y protegerse.