Redis®*: Ricerca e JSON

Archivia documenti JSON ed esegui query in modo efficiente con il motore di ricerca Redis

👋 Benvenuti nella documentazione di Stackhero!

Stackhero offre una soluzione Redis cloud pronta all'uso che garantisce numerosi vantaggi, tra cui:

  • Interfaccia web Redis Commander inclusa.
  • Dimensione e trasferimento dei messaggi illimitati.
  • Aggiornamenti semplici con un solo clic.
  • Prestazioni ottimali e sicurezza avanzata grazie a un'infrastruttura privata e dedicata.

Risparmia tempo e semplificati la vita: bastano 5 minuti per provare la soluzione di hosting Redis cloud di Stackhero!

La tua istanza Redis su Stackhero include tutti i moduli disponibili in Redis Open Source. Questi moduli rendono Redis molto più di una semplice cache: puoi archiviare veri documenti JSON, indicizzarli ed eseguire query full-text, numeriche e per tag direttamente. Non è necessario aggiungere un altro database al tuo stack.

Tutti e quattro i moduli seguenti sono inclusi nel tuo piano:

  • JSON (comandi JSON.*): Aggiunge un tipo JSON nativo con supporto JSONPath. Puoi leggere o aggiornare singoli campi senza riscrivere l'intero documento.
  • Search (comandi FT.*), noto anche come motore di ricerca Redis: Fornisce ricerca full-text, indicizzazione secondaria, aggregazioni e funzionalità di ricerca vettoriale.
  • Bloom (comandi BF.*, CF.*, CMS.*, TOPK.*, TDIGEST.*): Strutture dati probabilistiche che rispondono in modo efficiente a domande come "l'ho già visto?" su insiemi molto grandi utilizzando pochissima memoria.
  • Time series (comandi TS.*): Offre un tipo time series con funzionalità di retention, downsampling e aggregazione.

I vector sets (VADD, VSIM) sono integrati direttamente in Redis. Consentono una ricerca vettoriale efficiente per embeddings e sono sempre disponibili sul tuo servizio. Non è necessaria alcuna configurazione.

I moduli sono disabilitati per impostazione predefinita. Questo garantisce che i servizi esistenti mantengano il comportamento originale finché non scegli di abilitare nuove funzionalità.

  1. Apri il tuo servizio nella dashboard Stackhero.
  2. Vai alla configurazione del servizio.
  3. Nella sezione Modules, seleziona i moduli desiderati.
  4. Salva le modifiche.

Il tuo servizio Redis verrà riavviato con i moduli selezionati caricati. Questa operazione richiede solitamente pochi secondi.

Una volta che archivi dati utilizzando un modulo (come un documento JSON, un filtro Bloom o una time series), mantieni quel modulo abilitato. Redis non può accedere ai dati creati da un modulo disabilitato e la sua disabilitazione impedirà l'avvio del servizio. I vector sets sono sempre disponibili, in quanto parte integrante di Redis.

Per verificare quali moduli sono attualmente caricati, puoi eseguire:

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

Puoi archiviare documenti nativamente come JSON, invece di serializzarli come stringhe:

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

Questo approccio ti permette di leggere o aggiornare singoli campi in modo atomico e lato server:

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

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

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

Questo flusso di lavoro semplifica le operazioni e riduce gli errori. Ad esempio, decrementare un contatore di stock non richiede di leggere, analizzare e riscrivere l'intero documento nella tua applicazione: l'operazione avviene in modo sicuro e immediato sul server.

Puoi trovare l'elenco completo dei comandi nella documentazione Redis JSON.

È sufficiente dichiarare un indice una sola volta. Redis lo mantiene aggiornato automaticamente per ogni chiave che corrisponde al prefisso scelto, incluse le chiavi già esistenti prima della creazione dell'indice.

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

Ora puoi eseguire query come:

# Ricerca full-text sul nome, con intervallo di prezzo
FT.SEARCH productsIndex "@name:(espresso) @price:[0 500]"

# Ricerca esatta per brand, ordinata per prezzo
FT.SEARCH productsIndex "@brand:{Bianca}" SORTBY price ASC

# Ricerca per prefisso per scenari di autocompletamento
FT.SEARCH productsIndex "@name:(espr*)"

Redis può anche gestire aggregazioni direttamente sull'indice, così puoi rispondere a query analitiche senza esportare i dati:

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

Se archivi i dati in semplici hash invece che in JSON, puoi usare ON HASH e nomi di campo standard nello schema.

import { createClient, SCHEMA_FIELD_TYPE } from 'redis';

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

// Creazione dell'indice all'avvio
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)

# Creazione dell'indice all'avvio
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)
  • Gli indici Search funzionano solo sul database 0. FT.CREATE restituisce un errore su qualsiasi altro database. Se la tua applicazione utilizza più database logici, mantieni i dati indicizzabili sul database 0 oppure usa prefissi di chiave per separare i diversi dataset.
  • Gli indici utilizzano la memoria prevista dal tuo piano, proprio come i dati. Indici testuali o vettoriali di grandi dimensioni possono essere significativi, quindi puoi monitorare used_memory nelle tue metriche Prometheus dopo la loro creazione.
  • La creazione di un indice su chiavi esistenti avviene in background. Subito dopo FT.CREATE, le ricerche potrebbero restituire risultati incompleti per un breve periodo. Puoi monitorare l'avanzamento dell'indicizzazione con FT.INFO productsIndex.
  • Tutti i comandi dei moduli sono completamente disponibili. Ogni comando di ogni modulo abilitato è pronto all'uso sul tuo servizio.

Per approfondire la ricerca di similarità vettoriale, la semantic search o il retrieval-augmented generation, consulta la guida alla ricerca vettoriale.