Redis®*: Pesquisa e JSON

Armazene documentos JSON e faça consultas eficientes com o motor de pesquisa do Redis

👋 Bem-vindo à documentação da Stackhero!

A Stackhero disponibiliza uma solução Redis cloud pronta a usar, que oferece várias vantagens, incluindo:

  • Interface web Redis Commander incluída.
  • Tamanho e transferências de mensagens ilimitados.
  • Atualizações fáceis com apenas um clique.
  • Performance otimizada e segurança reforçada, graças a uma infraestrutura privada e dedicada.

Poupe tempo e simplifique a sua vida: bastam 5 minutos para experimentar a solução de alojamento Redis cloud da Stackhero!

A sua instância Redis na Stackhero inclui todos os módulos disponíveis no Redis Open Source. Estes módulos tornam o Redis muito mais do que uma cache: pode armazenar documentos JSON reais, indexá-los e executar pesquisas full-text, numéricas e por tags diretamente. Não é necessário adicionar outra base de dados à sua stack.

Todos os quatro módulos abaixo estão incluídos no seu plano:

  • JSON (comandos JSON.*): Adiciona um tipo JSON nativo com suporte a JSONPath. Pode ler ou atualizar campos individuais sem reescrever o documento inteiro.
  • Search (comandos FT.*), também conhecido como motor de pesquisa do Redis: Fornece pesquisa full-text, indexação secundária, agregações e capacidades de pesquisa vetorial.
  • Bloom (comandos BF.*, CF.*, CMS.*, TOPK.*, TDIGEST.*): Estruturas de dados probabilísticas que respondem de forma eficiente a perguntas como "já vi isto antes?" em conjuntos massivos, usando memória mínima.
  • Time series (comandos TS.*): Oferece um tipo time series com retenção, downsampling e funcionalidades de agregação.

Os vector sets (VADD, VSIM) estão integrados diretamente no Redis. Permitem pesquisa vetorial eficiente para embeddings e estão sempre disponíveis no seu serviço. Não é necessária qualquer configuração.

Os módulos estão desativados por predefinição. Isto garante que os serviços existentes mantêm o seu comportamento original até que decida ativar novas funcionalidades.

  1. Abra o seu serviço no dashboard da Stackhero.
  2. Aceda à configuração do serviço.
  3. Na secção Modules, selecione os módulos pretendidos.
  4. Guarde as alterações.

O seu serviço Redis irá reiniciar com os módulos selecionados carregados. Este processo normalmente demora apenas alguns segundos.

Depois de armazenar dados utilizando um módulo (como um documento JSON, filtro Bloom ou time series), mantenha esse módulo ativado. O Redis não consegue aceder a dados criados por um módulo desativado e desativá-lo impedirá o arranque do seu serviço. Os vector sets estão sempre disponíveis, pois fazem parte do próprio Redis.

Para verificar quais os módulos atualmente carregados, pode executar:

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

Pode armazenar documentos nativamente como JSON, em vez de os serializar como strings:

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

Esta abordagem permite-lhe ler ou atualizar campos individuais de forma atómica e do lado do servidor:

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

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

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

Este fluxo de trabalho simplifica o desenvolvimento e reduz erros. Por exemplo, para decrementar um contador de stock não é necessário ler, analisar e reescrever todo o documento na sua aplicação. Em vez disso, a operação é feita de forma segura e imediata no servidor.

Pode consultar a lista completa de comandos na documentação Redis JSON.

Só precisa de declarar um índice uma vez. O Redis mantém-no atualizado automaticamente para cada chave que corresponda ao prefixo escolhido, incluindo chaves que já existiam antes da criação do í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

Agora pode executar consultas como:

# Pesquisa full-text no nome, com intervalo de preço
FT.SEARCH productsIndex "@name:(espresso) @price:[0 500]"

# Correspondência exata da marca, ordenada por preço
FT.SEARCH productsIndex "@brand:{Bianca}" SORTBY price ASC

# Pesquisa por prefixo para cenários de autocompletar
FT.SEARCH productsIndex "@name:(espr*)"

O Redis também pode realizar agregações diretamente sobre o índice, permitindo responder a consultas analíticas sem exportar dados:

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

Se armazenar dados em hashes simples em vez de JSON, pode usar ON HASH e nomes de campos standard no seu esquema.

import { createClient, SCHEMA_FIELD_TYPE } from 'redis';

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

// Criar o índice no arranque
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)

# Criar o índice no arranque
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)
  • Os índices Search só funcionam na base de dados 0. FT.CREATE devolve um erro em qualquer outra base de dados. Se a sua aplicação usar várias bases de dados lógicas, mantenha os dados indexáveis na base 0 ou utilize prefixos de chave para separar diferentes conjuntos de dados.
  • Os índices utilizam a memória do seu plano, tal como os seus dados. Índices de texto ou vetoriais de grande dimensão podem ser significativos, por isso monitorize o used_memory nas suas métricas Prometheus após a sua criação.
  • A criação de um índice sobre chaves existentes é feita em background. Imediatamente após o FT.CREATE, as pesquisas podem devolver resultados incompletos durante alguns instantes. Pode acompanhar o progresso da indexação com FT.INFO productsIndex.
  • Todos os comandos dos módulos estão totalmente disponíveis. Todos os comandos de cada módulo ativado estão prontos a usar no seu serviço.

Para saber mais sobre similaridade vetorial, pesquisa semântica ou retrieval-augmented generation, consulte o guia de pesquisa vetorial.