Come migliorare la qualità del recupero per il testo giapponese con Sudachi, Milvus/Zilliz e AWS Bedrock
Questo post è stato originariamente pubblicato su Qiita ed è tradotto e pubblicato qui con autorizzazione.
Introduzione
Quando ho iniziato a costruire sistemi Retrieval-Augmented Generation (RAG) per utenti giapponesi, mi sono imbattuto in un problema che probabilmente risulta familiare a chiunque abbia lavorato con testi giapponesi: l’accuratezza della ricerca non è semplicemente così lineare come in inglese. La lingua ha delle particolarità—variazioni ortografiche, vocali lunghe, scritture miste, differenze nelle forme superficiali—che spesso compromettono sia i metodi di retrieval densi sia quelli sparsi quando usati isolatamente.
La ricerca vettoriale densa è ottima per comprendere il contesto e la somiglianza semantica, ma crolla rapidamente quando servono corrispondenze esatte—numeri di modello, identificatori di articoli di legge, codici interni o entità molto specifiche come “金商法第37条 (Articolo 37 della Legge sugli strumenti finanziari e sugli scambi).” I metodi basati su parole chiave come BM25 gestiscono bene questi casi, ma non riescono a stare al passo quando l’input include piccole variazioni ortografiche (“サーバー” vs. “サーバ”) o quando la stessa idea può essere espressa in forme diverse.
Per aggirare il problema, ho costruito una pipeline di ricerca ibrida che combina i punti di forza di entrambi gli approcci. La soluzione utilizza:
Sudachi: un tokenizer giapponese che fornisce normalizzazione e tokenizzazione stabile su testi incoerenti.
Zilliz Cloud (il servizio Milvus completamente gestito): un database vettoriale ad alte prestazioni che supporta vettori densi, vettori sparsi e persino la generazione automatica di vettori BM25, il che rende la ricerca ibrida molto più facile da implementare.
AWS Bedrock: utilizzato per generare embedding densi di alta qualità (Titan Embeddings v2), che costituiscono il lato semantico della pipeline di retrieval.
In questo post, illustrerò come ho messo insieme questi componenti per costruire un sistema di ricerca ibrida giapponese ad alta accuratezza. Includerò anche un esempio pratico, così potrai provare tu stesso lo stesso flusso di lavoro e adattarlo ai tuoi progetti RAG.
Panoramica dell’architettura
Il sistema di ricerca ibrida in questo articolo è costruito su uno stack semplice ma efficace. Ogni componente risolve un problema specifico che emerge quando si lavora con testi giapponesi, e insieme formano una pipeline di retrieval che bilancia comprensione semantica e precisione delle corrispondenze esatte. Ecco la suddivisione di com’è fatto lo stack e perché ogni parte è importante.
SudachiPy — Tokenizer / Analisi morfologica
Il testo giapponese contiene spesso grafie incoerenti, irregolarità nella spaziatura e variazioni nella notazione. Invece di affidarmi a una tokenizzazione ingenua, uso SudachiPy e la sua API normalized_form() per ripulire tutto. Questo garantisce che “サーバー” e “サーバ” vengano mappati allo stesso token normalizzato, e che i documenti che altrimenti verrebbero persi compaiano comunque nei risultati di ricerca. Questo singolo passaggio migliora drasticamente il recall su tutta la linea.
Zilliz Cloud (Managed Milvus): un database vettoriale ad alte prestazioni
Milvus è il database vettoriale open-source più ampiamente adottato, con oltre 43K star su GitHub e un vasto ecosistema di contributor. Zilliz Cloud usa lo stesso core di Milvus, ma elimina tutto il lavoro operativo—configurazione del cluster, autoscaling, ottimizzazione delle prestazioni, backup, aggiornamenti di versione—pur esponendo la stessa API di Milvus. In pratica, questo significa che posso sviluppare localmente con Milvus open-source e distribuire lo stesso identico codice su Zilliz Cloud quando ho bisogno di un ambiente di livello production-grade.
Questo è importante perché molti progetti di ricerca vettoriale incontrano lo stesso ostacolo: il prototipo funziona, ma scalarlo diventa troppo costoso o troppo imprevedibile. I servizi di ricerca PaaS completamente gestiti come Azure AI Search o gli archivi vettoriali proprietari spesso diventano colli di bottiglia dei costi molto prima che i requisiti prestazionali siano soddisfatti. Zilliz Cloud offre un percorso più efficiente: maggiore throughput, minore latenza e più controllo sul layout dei dati—senza l’aumento progressivo dei costi che di solito compare su larga scala.
In questa architettura, Zilliz Cloud gestisce tutto lo storage e il recupero degli embedding. Supporta:
Ricerca vettoriale densa per la similarità semantica
Ricerca vettoriale sparsa per il recupero basato su parole chiave
A partire da Milvus v2.4, il database include anche una funzionalità Function che genera automaticamente vettori sparsi BM25 dal testo grezzo. Questo è un grande vantaggio operativo. Non devo calcolare BM25 lato client, mantenere pipeline di indicizzazione aggiuntive o sincronizzare metadati tra più sistemi. Tutto—dagli embedding densi a BM25 fino al ranking ibrido—risiede in un unico database, mantenendo l’intero workflow di recupero semplice, veloce e facile da mantenere.
AWS Bedrock (Titan Embeddings v2): Il modello di embedding
Per gli embedding vettoriali densi, utilizzo Titan Embeddings v2 di AWS Bedrock. Funziona bene in più lingue e gestisce il testo giapponese in modo affidabile, cosa importante quando si esegue l’embedding di contenuti misti come query brevi, lunghi documenti di policy, descrizioni di prodotti e testi in stile FAQ.
Reciprocal Rank Fusion (RRF): Il metodo di reranking
La ricerca ibrida funziona solo se è possibile combinare in modo significativo i risultati della ricerca densa e sparsa, e i due spazi di punteggio sono fondamentalmente diversi. RRF (Reciprocal Rank Fusion) risolve questo problema in modo pulito fondendo i risultati in base al rank anziché ai punteggi grezzi. Produce risultati ibridi stabili e facili da comprendere, senza alcuna ponderazione regolata manualmente o trucchi di normalizzazione.
Tutorial di ricerca ibrida adatto ai principianti
Tolto di mezzo l’aspetto architetturale, passiamo a qualcosa che puoi effettivamente eseguire. Ho preparato un repo GitHub con tutto il codice e i dati di esempio necessari, quindi la configurazione è intenzionalmente leggera. Dopo aver avviato un cluster Zilliz Cloud gratuito e aggiunto la tua chiave API AWS Bedrock, potrai testare tre modalità di recupero fianco a fianco:
Ricerca vettoriale densa
Ricerca full-text sparsa (BM25)
Ricerca ibrida (fusione RRF)
L’intero workflow viene eseguito a basso costo—solo le chiamate agli embedding di Bedrock comportano addebiti.
Step 1: Clonare il repository da GitHub
Per prima cosa, clona il repository:
git clone [https://github.com/Beginnersguide138/rag-with-sudachi.git](https://github.com/Beginnersguide138/rag-with-sudachi.git)
Spostati nella directory del progetto e configura l’ambiente Python:
cd rag-with-sudachi
uv sync # Install Python dependencies using uv
cp .env.example .env # Create an environment file based on the template
Step 2: Configurare Zilliz Cloud (Free Tier)
Zilliz Cloud funziona su tutti i principali cloud provider—AWS, GCP e Azure. Puoi registrarti direttamente sul sito web di Zilliz o sottoscrivere il servizio tramite i rispettivi marketplace cloud. In questo tutorial, userò il percorso AWS Marketplace perché è un modo rapido per avviare un cluster Milvus completamente gestito senza toccare alcuna infrastruttura.
- Vai alla scheda di Zilliz Cloud su AWS Marketplace e fai clic su “Try for free.” Questo crea un cluster Milvus serverless a costo zero:
non passerà mai automaticamente a un piano a pagamento
Presenta alcune limitazioni (ad es., funzionalità di monitoraggio limitate)
Il cluster è più che sufficiente per questo tutorial sulla ricerca ibrida
2. Apri la console di Zilliz Cloud al termine dell’abbonamento:
Crea una nuova Organization (solo un contenitore logico per i tuoi progetti).
Vedrai un cluster serverless gratuito già predisposto.
Recupera il Cluster Endpoint e la API Key: ti serviranno quando ti connetterai dal tuo codice.
Passaggio 3: Configurare le variabili d’ambiente
Incolla le tue credenziali Zilliz e Bedrock nel file .env:
# Zilliz Cloud connection
ZILLIZ_CLOUD_URI=https://your-cluster-id.serverless.region.cloud.zilliz.com
ZILLIZ_CLOUD_API_KEY=your-api-key-here
# AWS Bedrock short-term API key
AWS_BEARER_TOKEN_BEDROCK=bedrock-api-key-your-token-here
Nota sul codice: i token a breve termine di Bedrock scadono ogni 12 ore. È intenzionale: riducono il raggio d’impatto dell’esposizione delle credenziali e sono ideali per lo sviluppo locale.
Passaggio 4: Avviare il Notebook o eseguire lo script
Apri il repository in VS Code. Il tutorial principale si trova in:
notebooks/hybrid_search_with_bm25.ipynb
Se preferisci un flusso di lavoro Python puro invece di Jupyter Notebook, puoi eseguire:
python run_hybrid_search.py
Entrambe le versioni:
Creano lo schema Milvus
Applicano la normalizzazione Sudachi
Inseriscono vettori densi e sparsi
Confrontano i risultati della ricerca semantica, per parole chiave e ibrida
Dettagli tecnici
1. La chiave per l’elaborazione del giapponese: normalizzazione del testo con Sudachi
Nei sistemi di recupero per contenuti in giapponese, gran parte dell’accuratezza dipende da come il testo viene pre-elaborato durante l’indicizzazione. Il testo estratto dai PDF contiene spesso spaziatura incoerente, variazioni ortografiche o rumore, il che porta frequentemente a corrispondenze mancate e a un richiamo più basso.
Per affrontare questo problema, questa implementazione utilizza la funzione di normalizzazione di Sudachi. Questo processo standardizza i token prima dell’indicizzazione, in modo che il sistema di ricerca possa trattare grafie e rappresentazioni diverse come equivalenti.
Codice: wrapper di normalizzazione Sudachi
class SudachiAnalyzer:
def __init__(self):
self.tokenizer = dictionary.Dictionary(dict="core").create()
self.mode = tokenizer.Tokenizer.SplitMode.C
def analyze(self, text: str) -> str:
if not text:
return ""
tokens = self.tokenizer.tokenize(text, self.mode)
# Return as a space-separated string
return " ".join(\[t.normalized_form() for t in tokens if t.surface().strip()\])
analyzer = SudachiAnalyzer()
Perché la normalizzazione è importante
L’uso di normalized_form() unifica variazioni come:
Katakana: 「サーバー」 ⇔ 「サーバ」
Notazione numerica: 「第1条」 ⇔ 「第一条」
Rumore di spaziatura nei PDF: 「第 一 条」(不自然なスペース) ⇔ 「第一条」
Senza normalizzazione, queste variazioni portano a:
Corrispondenze BM25 mancate
Tokenizzazione errata dei vettori sparsi
Richiamo più basso per query strutturate legalmente
Normalizzando sia i documenti sia le query, il sistema ibrido aumenta drasticamente la probabilità di corrispondenza.
2. Progettazione dello schema in Zilliz Cloud (Milvus gestito)
Milvus, il nucleo di Zilliz Cloud, fornisce una funzionalità Function (disponibile dalla v2.4 in poi) che genera automaticamente vettori sparsi basati su BM25 nel database. Questo elimina la necessità di precomputare i vettori BM25 lato client.
Definizione dello schema
# Create schema (auto ID disabled for explicit ID assignment)
schema = MilvusClient.create_schema(auto_id=False, enable_dynamic_field=True)
# Field definitions
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
schema.add_field(
field_name="text",
datatype=DataType.VARCHAR,
max_length=65535,
enable_analyzer=True,
analyzer_params={
"tokenizer": "whitespace"
}, # Sudachi already provides whitespace-separated input
)
schema.add_field(
field_name="dense_vector", datatype=DataType.FLOAT_VECTOR, dim=1024
) # Titan Embeddings v2 outputs 1024 dimensions
schema.add_field(field_name="sparse_vector", datatype=DataType.SPARSE_FLOAT_VECTOR)
# Define the BM25 function
bm25_function = Function(
name="text_bm25_emb",
input_field_names=\["text"\],
output_field_names=\["sparse_vector"\],
function_type=FunctionType.BM25,
)
schema.add_function(bm25_function)
Questo design elimina la necessità di passare esplicitamente vettori sparsi durante l’inserimento dei dati, riducendo significativamente la complessità operativa.
Spostando la generazione dei vettori BM25 all’interno di Milvus stesso:
La pipeline di ingestione diventa più semplice
Non è richiesto alcun calcolo esplicito dei vettori sparsi
Si evita di mantenere codice di preprocessing aggiuntivo
La scalabilità diventa molto più semplice
Questo riduce significativamente l’onere operativo.
Progettazione dell’indice e strategia di ottimizzazione
# Index definitions
index_params = client.prepare_index_params()
index_params.add_index(
field_name="dense_vector", index_type="HNSW", metric_type="COSINE"
)
index_params.add_index(
field_name="sparse_vector",
index_type="SPARSE_INVERTED_INDEX",
metric_type="BM25",
params={"inverted_index_algo": "DAAT_MAXSCORE"},
)
Indice vettoriale denso: HNSW
HNSW (Hierarchical Navigable Small World) è un algoritmo ANN basato su grafi ampiamente utilizzato nei database vettoriali. Offre:
Recupero ad alta velocità
Elevato recall
Prestazioni solide su larga scala
COSINE è usato come metrica di similarità perché Titan Embeddings opera in uno spazio coseno normalizzato.
Indice vettoriale sparso: indice invertito con ottimizzazione MaxScore
I vettori sparsi usano una struttura tradizionale a indice invertito. L’ottimizzazione aggiuntiva DAAT_MAXSCORE fornisce:
Elaborazione document-at-a-time per un attraversamento efficiente
Potatura anticipata dei documenti che non possono raggiungere i punteggi top-k
Riduzione del calcolo senza compromettere l’accuratezza
Questo porta a una ricerca BM25 significativamente più rapida.
3. Implementazione della ricerca ibrida usando RRF
Per unire equamente i risultati delle ricerche dense (semantiche) e sparse (per parole chiave), il sistema usa Reciprocal Rank Fusion (RRF). RRF è robusto, facile da applicare e non richiede tuning o normalizzazione tra tipi di punteggio.
Codice di ricerca ibrida
from pymilvus import AnnSearchRequest, RRFRanker
def search_hybrid(client, collection_name, query_text, query_vector, top_k=5):
# Normalize and tokenize the query using Sudachi
query_processed = analyzer.analyze(query_text)
# Dense semantic search request
req_dense = AnnSearchRequest(
data=\[query_vector\],
anns_field="dense_vector",
param={"metric_type": "COSINE"},
limit=top_k * 2,
)
# Sparse BM25 keyword search request
req_sparse = AnnSearchRequest(
data=\[query_processed\],
anns_field="sparse_vector",
param={"metric_type": "BM25"},
limit=top_k * 2,
)
# Perform hybrid search using RRF
res = client.hybrid_search(
collection_name=collection_name,
reqs=\[req_dense, req_sparse\],
ranker=RRFRanker(), # Fuse rankings using RRF
limit=top_k,
output_fields=\["text", "original_text"\],
)
return res\[0\]
Confronto dei risultati di ricerca effettivi
Il tutorial valuta i risultati utilizzando documenti disponibili pubblicamente della Financial Services Agency giapponese. Il notebook consente un confronto affiancato di:
Ricerca semantica (vettore denso)
Ricerca full-text (vettore sparso)
Ricerca ibrida (densa + sparsa tramite RRF)
Caso di studio: query fortemente basata su parole chiave
Query: “指定ADR機関が存在しない場合の苦情処理措置”
Nota: la query significa “Una procedura per la gestione dei reclami quando non esiste un’organizzazione ADR designata.”
Risultati:
Ricerca vettoriale densa: restituisce spesso passaggi concettualmente correlati, ma fatica a far emergere clausole normative esatte.
Ricerca sparsa BM25: identifica correttamente i documenti contenenti termini come “designated ADR organization” e “complaint-handling measures,” classificandoli più in alto.
Ricerca ibrida: combina la capacità di corrispondenza precisa di BM25 con ulteriore contesto pertinente recuperato dalla ricerca densa.
Questo dimostra che la ricerca solo densa rischia di perdere risultati critici quando gli utenti effettuano query con terminologia specialistica. La ricerca ibrida è essenziale per il recupero di documenti aziendali.
Riepilogo e applicazioni
In questo articolo, abbiamo esaminato una configurazione pratica di ricerca ibrida che abbina la normalizzazione basata su Sudachi a Zilliz Cloud (Milvus gestito). L’obiettivo era semplice: creare una pipeline di recupero che funzioni bene sul testo giapponese, dove contano sia la similarità semantica sia la corrispondenza esatta. Combinando vettori densi, vettori sparsi BM25 e fusione basata su RRF, il sistema rimane accurato, facile da eseguire e adattabile a carichi di lavoro reali in produzione.
Vantaggi principali
Resistente alle variazioni ortografiche: la normalizzazione di Sudachi attenua differenze ortografiche, problemi di spaziatura e rumore di estrazione dai PDF, prevenendo comuni fallimenti di recall nella ricerca di testo giapponese.
Basso overhead operativo: Milvus Functions gestisce la generazione di vettori sparsi BM25 all’interno del database. Nessun job di preprocessing aggiuntivo, nessun servizio di ricerca esterno e nessuna logica di indicizzazione duplicata.
Elevata accuratezza complessiva: RRF combina il recupero denso e sparso senza complessa regolazione dei pesi. Si ottengono risultati ibridi stabili che gestiscono con eleganza sia query concettuali sia identificatori esatti.
Potenziali casi d’uso
Questo approccio ibrido eccelle negli scenari in cui gli utenti possono passare da query precise e strutturate a un linguaggio aperto:
Ricerca in policy e manuali interni: supporta riferimenti esatti (ad es., numeri di articoli) gestendo al contempo query vaghe o esplorative.
Ricerca prodotti e-commerce: consente la ricerca precisa per numero di parte offrendo al contempo raccomandazioni basate sulla similarità.
Knowledge base per l’assistenza clienti: abbina termini strutturati come codici di errore continuando a interpretare l’input naturale dell’utente (“画面が真っ黒です”, “ログインできない”).
Il codice sorgente completo e il Jupyter Notebook utilizzati in questo articolo sono disponibili nel seguente repository: GitHub: rag-with-sudachi
Il costo per provare tutto è minimo: vengono addebitate solo le chiamate di embedding AWS Bedrock. Il livello serverless gratuito di Zilliz Cloud è sufficiente per eseguire l’intero workflow.
Se stai esplorando la ricerca ibrida per sistemi di produzione o prototipi interni, questo esempio è un ottimo punto di partenza.
Continua a leggere

Introducing Functions and Model Inference on Zilliz Cloud: Automatic Embedding and Reranking with Hosted Models
Zilliz Cloud Functions auto-generate embeddings via OpenAI, Voyage AI, Cohere, or Zilliz Hosted Models. Built-in reranking — just insert text and search.

Why I’m Against Claude Code’s Grep-Only Retrieval? It Just Burns Too Many Tokens
Learn how vector-based code retrieval cuts Claude Code token consumption by 40%. Open-source solution with easy MCP integration. Try claude-context today.

Building RAG Pipelines for Real-Time Data with Cloudera and Milvus
explore how Cloudera can be integrated with Milvus to effectively implement some of the key functionalities of RAG pipelines.



