Redis®*: Búsqueda y JSON

Almacene documentos JSON y consúltelos de forma eficiente con el motor de consultas de Redis

👋 ¡Bienvenido a la documentación de Stackhero!

Stackhero ofrece una solución Redis cloud lista para usar que proporciona numerosas ventajas, entre ellas:

  • Interfaz web Redis Commander incluida.
  • Tamaño y transferencia de mensajes ilimitados.
  • Actualizaciones sencillas con solo un clic.
  • Rendimiento óptimo y seguridad reforzada gracias a una infraestructura privada y dedicada.

Ahorre tiempo y simplifique su trabajo: solo necesita 5 minutos para probar la solución de alojamiento Redis cloud de Stackhero.

Su instancia de Redis en Stackhero incluye todos los módulos disponibles en Redis Open Source. Estos módulos convierten Redis en mucho más que una caché: puede almacenar documentos JSON reales, indexarlos y realizar búsquedas de texto completo, numéricas y por etiquetas directamente. No es necesario añadir otra base de datos a su stack.

Los siguientes cuatro módulos están incluidos en su plan:

  • JSON (comandos JSON.*): Añade un tipo JSON nativo con soporte para JSONPath. Puede leer o actualizar campos individuales sin tener que reescribir el documento completo.
  • Search (comandos FT.*), también conocido como el motor de consultas de Redis: Proporciona búsqueda de texto completo, indexación secundaria, agregaciones y capacidades de búsqueda vectorial.
  • Bloom (comandos BF.*, CF.*, CMS.*, TOPK.*, TDIGEST.*): Estructuras de datos probabilísticas que permiten responder de forma eficiente a preguntas como "¿ya he visto esto?" sobre conjuntos masivos utilizando una cantidad mínima de memoria.
  • Time series (comandos TS.*): Ofrece un tipo de serie temporal con retención, downsampling y funciones de agregación.

Los vector sets (VADD, VSIM) están integrados directamente en Redis. Permiten búsquedas vectoriales eficientes para embeddings y siempre están disponibles en su servicio. No necesita realizar ninguna configuración.

Los módulos están desactivados por defecto. Esto garantiza que los servicios existentes mantengan su comportamiento original hasta que decida activar nuevas funcionalidades.

  1. Abra su servicio en el panel de Stackhero.
  2. Acceda a la configuración del servicio.
  3. En la sección Modules, seleccione los módulos que desee.
  4. Guarde los cambios.

Su servicio Redis se reiniciará con los módulos seleccionados cargados. Este proceso suele completarse en unos segundos.

Una vez que almacene datos utilizando un módulo (como un documento JSON, un filtro Bloom o una serie temporal), mantenga ese módulo activado. Redis no puede acceder a los datos creados por un módulo desactivado y, si lo desactiva, su servicio no podrá arrancar. Los vector sets siempre están disponibles, ya que forman parte del propio Redis.

Para comprobar qué módulos están actualmente cargados, puede ejecutar:

redis-cli -u "rediss://default:<yourPassword>@<XXXXXX>.stackhero-network.com:<PORT_TLS>" MODULE LIST

Puede almacenar documentos de forma nativa como JSON, en lugar de serializarlos como cadenas de texto:

JSON.SET product:1 $ '{"name":"Espresso machine","brand":"Bianca","price":459,"tags":["coffee","kitchen"],"stock":12}'

Este enfoque le permite leer o actualizar campos individuales de forma atómica y en el lado del servidor:

JSON.GET product:1 $.price
# "[459]"

JSON.NUMINCRBY product:1 $.stock -1
# "[11]"

JSON.ARRAPPEND product:1 $.tags '"gift"'

Este flujo de trabajo ahorra esfuerzo y reduce errores. Por ejemplo, decrementar un contador de stock no requiere leer, analizar y reescribir todo el documento en su aplicación. En su lugar, la operación se realiza de forma segura e inmediata en el servidor.

Puede consultar la lista completa de comandos en la documentación de Redis JSON.

Solo necesita declarar un índice una vez. Redis lo mantendrá actualizado automáticamente para cada clave que coincida con el prefijo elegido, incluidas las claves que ya existían antes de crear el índice.

FT.CREATE productsIndex
  ON JSON
  PREFIX 1 product:
  SCHEMA
    $.name AS name TEXT
    $.brand AS brand TAG
    $.price AS price NUMERIC SORTABLE
    $.tags[*] AS tags TAG

Ahora puede realizar consultas como:

# Búsqueda de texto completo en el nombre, con un rango de precios
FT.SEARCH productsIndex "@name:(espresso) @price:[0 500]"

# Coincidencia exacta de la marca, ordenada por precio
FT.SEARCH productsIndex "@brand:{Bianca}" SORTBY price ASC

# Búsqueda por prefijo para escenarios de autocompletado
FT.SEARCH productsIndex "@name:(espr*)"

Redis también puede realizar agregaciones directamente sobre el índice, por lo que puede responder a consultas analíticas sin exportar los datos:

FT.AGGREGATE productsIndex "*"
  GROUPBY 1 @brand
  REDUCE COUNT 0 AS products
  REDUCE AVG 1 @price AS averagePrice
  SORTBY 2 @products DESC

Si almacena los datos en hashes simples en lugar de JSON, puede usar ON HASH y nombres de campo estándar en su esquema.

import { createClient, SCHEMA_FIELD_TYPE } from 'redis';

const client = createClient({ url: process.env.STACKHERO_REDIS_URL_TLS });
await client.connect();

// Crear el índice al iniciar
try {
  await client.ft.create(
    'productsIndex',
    {
      '$.name': { type: SCHEMA_FIELD_TYPE.TEXT, AS: 'name' },
      '$.brand': { type: SCHEMA_FIELD_TYPE.TAG, AS: 'brand' },
      '$.price': { type: SCHEMA_FIELD_TYPE.NUMERIC, AS: 'price', SORTABLE: true }
    },
    { ON: 'JSON', PREFIX: 'product:' }
  );
}
catch (error) {
  if (!error.message.includes('Index already exists')) {
    throw error;
  }
}

await client.json.set('product:1', '$', {
  name: 'Espresso machine',
  brand: 'Bianca',
  price: 459
});

const results = await client.ft.search('productsIndex', '@name:(espresso) @price:[0 500]');
console.log(results.total, results.documents);

await client.quit();
import os
import redis
from redis.commands.search.field import TextField, TagField, NumericField
from redis.commands.search.index_definition import IndexDefinition, IndexType
from redis.commands.search.query import Query

r = redis.from_url(os.environ['STACKHERO_REDIS_URL_TLS'], decode_responses=True)

# Crear el índice al iniciar
try:
    r.ft('productsIndex').create_index(
        (
            TextField('$.name', as_name='name'),
            TagField('$.brand', as_name='brand'),
            NumericField('$.price', as_name='price', sortable=True),
        ),
        definition=IndexDefinition(prefix=['product:'], index_type=IndexType.JSON),
    )
except redis.ResponseError as error:
    if 'Index already exists' not in str(error):
        raise

r.json().set('product:1', '$', {
    'name': 'Espresso machine',
    'brand': 'Bianca',
    'price': 459,
})

results = r.ft('productsIndex').search(Query('@name:(espresso) @price:[0 500]'))
print(results.total, results.docs)
  • Los índices de Search solo funcionan en la base de datos 0. FT.CREATE devuelve un error en cualquier otra base de datos. Si su aplicación utiliza varias bases de datos lógicas, mantenga los datos indexables en la base de datos 0, o utilice prefijos de clave para separar los distintos conjuntos de datos.
  • Los índices utilizan la memoria de su plan, igual que sus datos. Los índices de texto o vectoriales grandes pueden ser significativos, así que puede monitorizar used_memory en sus métricas de Prometheus después de crearlos.
  • La creación de un índice sobre claves existentes se realiza en segundo plano. Justo después de FT.CREATE, las búsquedas pueden devolver resultados incompletos durante un breve periodo. Puede monitorizar el progreso de la indexación con FT.INFO productsIndex.
  • Todos los comandos de los módulos están completamente disponibles. Cada comando de cada módulo activado está listo para usar en su servicio.

Para obtener más información sobre búsqueda vectorial, búsqueda semántica o retrieval-augmented generation, consulte la guía de búsqueda vectorial.