Redis®*: Wyszukiwanie i JSON

Przechowuj dokumenty JSON i efektywnie je przeszukuj za pomocą silnika zapytań Redis

👋 Witamy w dokumentacji Stackhero!

Stackhero oferuje gotowe do użycia rozwiązanie Redis cloud, które zapewnia szereg korzyści, w tym:

  • Wbudowany web UI Redis Commander.
  • Nieograniczona wielkość i transfer wiadomości.
  • Bezproblemowe aktualizacje za pomocą jednego kliknięcia.
  • Optymalna wydajność i wysoki poziom bezpieczeństwa dzięki prywatnej, dedykowanej infrastrukturze.

Oszczędzaj czas i uprość sobie życie: wystarczy 5 minut, aby przetestować rozwiązanie hostingu Redis cloud od Stackhero!

Twoja instancja Redis na Stackhero zawiera wszystkie moduły dostępne w Redis Open Source. Te moduły sprawiają, że Redis to znacznie więcej niż tylko cache: możesz przechowywać prawdziwe dokumenty JSON, indeksować je oraz wykonywać zapytania full-text, numeryczne i po tagach bezpośrednio. Nie ma potrzeby dodawania kolejnej bazy danych do swojego stacka.

Wszystkie cztery poniższe moduły są dostępne w Twoim planie:

  • JSON (polecenia JSON.*): Dodaje natywny typ JSON z obsługą JSONPath. Pozwala to na odczyt lub aktualizację pojedynczych pól bez konieczności przepisywania całego dokumentu.
  • Search (polecenia FT.*), znany również jako silnik zapytań Redis: Zapewnia wyszukiwanie full-text, indeksowanie wtórne, agregacje oraz wyszukiwanie wektorowe.
  • Bloom (polecenia BF.*, CF.*, CMS.*, TOPK.*, TDIGEST.*): Probabilistyczne struktury danych, które pozwalają efektywnie odpowiadać na pytania typu "czy już to widziałem?" na bardzo dużych zbiorach, przy minimalnym zużyciu pamięci.
  • Time series (polecenia TS.*): Udostępnia typ szeregów czasowych z funkcjami retencji, downsamplingu i agregacji.

Vector sets (VADD, VSIM) są wbudowane bezpośrednio w Redis. Umożliwiają wydajne wyszukiwanie podobieństwa wektorowego dla embeddingów i są zawsze dostępne w Twojej usłudze. Nie wymagają żadnej konfiguracji.

Moduły są domyślnie wyłączone. Dzięki temu istniejące usługi zachowują swoje pierwotne zachowanie, dopóki nie zdecydujesz się włączyć nowych funkcji.

  1. Otwórz swoją usługę w panelu Stackhero.
  2. Przejdź do konfiguracji usługi.
  3. W sekcji Modules wybierz interesujące Cię moduły.
  4. Zapisz zmiany.

Twoja usługa Redis zostanie zrestartowana z wybranymi modułami. Proces ten zazwyczaj trwa kilka sekund.

Po zapisaniu danych za pomocą modułu (np. dokumentu JSON, filtra Bloom lub szeregu czasowego), pozostaw ten moduł włączony. Redis nie ma dostępu do danych utworzonych przez wyłączony moduł, a jego wyłączenie uniemożliwi uruchomienie usługi. Vector sets są zawsze dostępne, ponieważ są częścią samego Redis.

Aby sprawdzić, które moduły są aktualnie załadowane, możesz wykonać:

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

Możesz przechowywać dokumenty natywnie jako JSON, zamiast serializować je do stringów:

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

Takie podejście pozwala na atomowy odczyt lub aktualizację pojedynczych pól po stronie serwera:

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

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

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

To rozwiązanie upraszcza obsługę i ogranicza ryzyko błędów. Na przykład dekrementacja licznika stanu magazynowego nie wymaga odczytu, parsowania i ponownego zapisu całego dokumentu w aplikacji – operacja jest wykonywana natychmiast i bezpiecznie po stronie serwera.

Pełną listę poleceń znajdziesz w dokumentacji Redis JSON.

Indeks deklarujesz tylko raz. Redis automatycznie utrzymuje go w aktualności dla każdego klucza pasującego do wybranego prefixu, w tym kluczy istniejących już przed utworzeniem indeksu.

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

Teraz możesz wykonywać zapytania takie jak:

# Wyszukiwanie full-text po nazwie, z zakresem cenowym
FT.SEARCH productsIndex "@name:(espresso) @price:[0 500]"

# Dokładne dopasowanie marki, sortowanie po cenie
FT.SEARCH productsIndex "@brand:{Bianca}" SORTBY price ASC

# Wyszukiwanie po prefiksie do autouzupełniania
FT.SEARCH productsIndex "@name:(espr*)"

Redis obsługuje także agregacje bezpośrednio na indeksie, dzięki czemu możesz wykonywać zapytania analityczne bez eksportowania danych:

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

Jeśli przechowujesz dane w zwykłych hashach zamiast JSON, możesz użyć ON HASH i standardowych nazw pól w swoim schemacie.

import { createClient, SCHEMA_FIELD_TYPE } from 'redis';

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

// Tworzenie indeksu przy starcie
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)

# Tworzenie indeksu przy starcie
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)
  • Indeksy Search działają tylko na bazie danych 0. FT.CREATE zwróci błąd na każdej innej bazie. Jeśli Twoja aplikacja korzysta z kilku baz logicznych, trzymaj dane do indeksowania w bazie 0 lub używaj prefiksów kluczy do rozdzielenia zbiorów danych.
  • Indeksy wykorzystują pamięć z Twojego planu, tak jak dane. Duże indeksy tekstowe lub wektorowe mogą być znaczące, dlatego po ich utworzeniu monitoruj used_memory w swoich metrykach Prometheus.
  • Budowanie indeksu na istniejących kluczach odbywa się w tle. Bezpośrednio po FT.CREATE wyszukiwania mogą przez chwilę zwracać niepełne wyniki. Postęp indeksowania możesz monitorować poleceniem FT.INFO productsIndex.
  • Wszystkie polecenia modułów są w pełni dostępne. Każde polecenie każdego włączonego modułu jest gotowe do użycia w Twojej usłudze.

Aby dowiedzieć się więcej o wyszukiwaniu podobieństwa wektorowego, wyszukiwaniu semantycznym lub retrieval-augmented generation, zobacz przewodnik po wyszukiwaniu wektorowym.