Strategia di Archiviazione: Valkey vs JSON vs NumPy

Questo articolo spiega perché utilizziamo diverse tecnologie di archiviazione per diversi tipi di dati nel pipeline SEO e nel servizio di ricerca.

Il Problema: Una Soluzione Non Va Bene per Tutto

Dati diversi hanno pattern di accesso diversi:

  • Embedding (5K x 384 float): Necessitano di operazioni vettoriali veloci (similarità del coseno)

  • Mappature di frasi (2500+ frasi): Necessitano di editing umano, controllo delle versioni

  • Cache delle query (query in tempo reale): Necessitano di ricerche chiave-valore veloci, scadenza TTL

  • Dati dei prodotti (64K prodotti): Necessitano di accesso strutturato, regole di compatibilità

Usare la stessa archiviazione per tutto sarebbe inefficiente.

Tre Tecnologie di Archiviazione

1. Array NumPy: Operazioni Vettoriali

Caso d'uso: Embedding (prodotti, query, frasi)

Perché NumPy:

  • Matematica vettoriale veloce: Librerie C/Fortran ottimizzate per operazioni matriciali

  • File mappati in memoria: Carica array di grandi dimensioni senza copiarli nella RAM

  • Operazioni in batch: Elabora migliaia di vettori in millisecondi

  • Formato standard: Compatibile con librerie ML (scikit-learn, TensorFlow)

Formato file: File binari .npy

Caricamento:

import numpy as np

# Mappato in memoria (non carica l'intero file nella RAM)
embeddings = np.load('embeddings.npy', mmap_mode='r')

# Calcola la similarità del coseno
from sklearn.metrics.pairwise import cosine_similarity
similarities = cosine_similarity(query_embedding, embeddings)

Prestazioni: ricerche di similarità massicce a velocità adatte per inferenza in tempo reale.

2. File JSON: Dati Editabili dall'Uomo

Caso d'uso: Configurazione, mappature, metadati

Perché JSON:

  • Leggibile dall'uomo: Facile da ispezionare e debuggare

  • Controllo delle versioni: Le differenze Git mostrano esattamente cosa è cambiato

  • Editing manuale: Possibilità di correggere errori senza codice

  • Formato universale: Ogni linguaggio può analizzare JSON

Cosa archiviamo:

  • Mappature frase-filtro: frasi → regole di filtro

  • Caratteristiche del prodotto: prodotti → dizionari di caratteristiche

  • Metadati delle query: query → clic, impressioni, sorgenti

  • Configurazione del pipeline: Parametri degli step, soglie

Formato file: File di testo .json

Caricamento:

import json

with open('phrase_mappings.json') as f:
    mappings = json.load(f)

# Accesso ai dati
filters = mappings['mini pc']  # ['form_factor:mini', 'category:pc']

3. Valkey (Redis): Cache Chiave-Valore Veloce

Caso d'uso: Ricerca in tempo reale, autocompletamento, query popolari

Perché Valkey:

  • In memoria: Latenza in microsecondi per le ricerche

  • RediSearch: Ricerca di similarità vettoriale con indici

  • Scadenza TTL: Invalidazione automatica della cache

  • Pub/sub: Aggiornamenti in tempo reale tra server

  • Persistenza: Snapshot su disco opzionali per durabilità

Cosa archiviamo:

  • Cache degli embedding delle query: Query recenti → embedding

  • Query popolari: Top 1000 query per traffico

  • Indice di autocompletamento: Prefisso → suggerimenti di query

  • Cache di estrazione filtri: Query → filtri estratti

  • Cache di ricerche correlate: Query → query correlate

Strutture dati:

  • Stringhe: Semplice chiave-valore (query → embedding)

  • Set ordinati: Dati classificati (query popolari per punteggio)

  • Indici RediSearch: Ricerca di similarità vettoriale

  • Hash: Dati strutturati (metadati query)

Caricamento:

from app.shared.valkey_cache import get_valkey

valkey = get_valkey()
# ... (dettagli implementativi omessi)

Matrice Decisionale

Quando Usare NumPy

Criteri:

  • I dati sono numerici (float, int)

  • Necessità di operazioni vettoriali veloci (prodotto scalare, similarità del coseno)

  • I dati sono prevalentemente in lettura (raramente aggiornati)

  • I dati sono di grandi dimensioni (milioni di numeri)

  • Elaborazione in batch (elabora molti elementi contemporaneamente)

Esempi:

  • Embedding (prodotti, query, frasi)

  • Vettori di caratteristiche

  • Matrici di similarità

Quando Usare JSON

Criteri:

  • I dati sono strutturati (oggetti, array)

  • Necessità di leggibilità umana

  • Necessità di controllo delle versioni (Git)

  • I dati cambiano occasionalmente (modifiche manuali)

  • I dati sono piccoli-medio (<100 MB)

Esempi:

  • File di configurazione

  • Mappature di frasi

  • Metadati del prodotto

  • Parametri del pipeline

Quando Usare Valkey

Criteri:

  • Necessità di ricerche veloci (microsecondi)

  • I dati cambiano frequentemente (query in tempo reale)

  • Necessità di scadenza TTL (invalidazione cache)

  • Necessità di pub/sub (aggiornamenti in tempo reale)

  • Necessità di ricerca vettoriale (RediSearch)

Esempi:

  • Cache delle query

  • Autocompletamento

  • Query popolari

  • Dati di sessione

  • Limitazione della frequenza

Approccio Ibrido

Combiniamo tutti e tre per prestazioni ottimali:

Pipeline (Elaborazione Offline)

NumPy: Calcola embedding, matrici di similarità

JSON: Archivia mappature, metadati, configurazione

Valkey: Non utilizzato (la pipeline funziona offline)

Servizio di Ricerca (Query in Tempo Reale)

NumPy: Carica embedding dal disco (mappati in memoria)

JSON: Carica mappature dal disco (cache in memoria)

Valkey: Cache delle query in tempo reale, autocompletamento, query popolari

Flusso dei Dati

graph LR
    Pipeline[Pipeline SEO
Offline] subgraph Storage NP[File NumPy
embeddings.npy] JS[File JSON
mappings.json] end Search[Servizio di Ricerca
Live] VK[Valkey
Cache] Pipeline --> NP Pipeline --> JS NP --> Search JS --> Search Search --> VK VK --> Search

Confronto delle Prestazioni

NumPy (mappato in memoria):

  • Tempo di caricamento: Istantaneo (mappatura zero-copy nella memoria virtuale)

  • Tempo di ricerca: Quasi zero (puntatore CPU diretto all'indice dell'array)

  • Memoria: Minima (cache di pagine gestita dal SO, non residente nella RAM del processo)

JSON:

  • Tempo di caricamento: Latenza elevata (analisi sequenziale e creazione oggetti)

  • Tempo di ricerca: Efficiente (overhead standard della mappa hash)

  • Memoria: Sostanziale (l'intera struttura serializzata risiede nell'heap)

Valkey:

  • Tempo di caricamento: Persistente (residente nel servizio in background)

  • Tempo di ricerca: Moderato (include round-trip di rete e serializzazione del protocollo)

  • Memoria: Esternalizzata (isolata all'interno del processo del database)

Vincitore: NumPy per l'elaborazione in batch ad alta velocità, Valkey per l'accesso distribuito a chiave singola

Ricerca di Similarità Vettoriale

NumPy (cosine_similarity):

  • Operazioni in batch: Rapide (ottimizzate tramite algebra lineare vettoriale/SIMD)

  • Parallelizzabile: Alta (si adatta a tutti i core CPU fisici disponibili)

  • Memoria: Lineare (si adatta direttamente alle dimensioni degli embedding)

Valkey (RediSearch):

  • Velocità di ricerca: Superiore (utilizza indicizzazione vettoriale HNSW/specializzata)

  • Parallelizzabile: Limitata (vincolata dal modello di threading del motore)

  • Memoria: Intensiva (richiede embedding grezzi più metadati di indicizzazione)

Vincitore: Valkey per la ricerca live sub-percettiva, NumPy per l'elaborazione analitica offline pesante

Ricerca di Configurazione

JSON:

  • Tempo di caricamento: Variabile (proporzionale alla complessità della configurazione)

  • Tempo di ricerca: Veloce (accesso al dizionario nativo)

  • Tempo di modifica: Senza attrito (modifica del testo leggibile dall'uomo)

Valkey:

  • Tempo di caricamento: Immediato (attivo alla connessione)

  • Tempo di ricerca: Vincolato dalla rete (dipendente dall'overhead della richiesta)

  • Tempo di modifica: Programmabile (richiede comandi CLI o SET del client)

Vincitore: JSON per configurazioni statiche, Valkey per stato condiviso dinamico

Riferimenti

Tecnologie

  • NumPy - Libreria per il calcolo con array

  • JSON - Formato di interscambio dati

  • Valkey - Archivio dati in memoria (fork di Redis)

  • RediSearch - Modulo per ricerca vettoriale

Concetti Tecnici

Articoli Correlati

Riepilogo

Utilizziamo tre tecnologie di archiviazione ottimizzate per diversi casi d'uso:

NumPy (embedding):

  • Operazioni vettoriali veloci (similarità del coseno)

  • Mappato in memoria

  • Elaborazione in batch

  • Formato ML standard

JSON (configurazione):

  • Leggibile dall'uomo (facile debug)

  • Controllo delle versioni (differenze Git)

  • Modifica manuale (nessun codice necessario)

  • Formato universale

Valkey (cache live):

  • Ricerche veloci (microsecondi)

  • Ricerca vettoriale (RediSearch)

  • Scadenza TTL (auto-invalidazione)

  • Pub/sub (aggiornamenti in tempo reale)

Approccio ibrido: Usa lo strumento giusto per ogni lavoro, combinali per prestazioni ottimali.


← Torna all'Indice della Documentazione