Ricerca ibrida 2.0: la ricerca di una ricerca migliore |  di Noam Schwartz |  Settembre 2023

 | Intelligenza-Artificiale

  1. La funzione di normalizzazione era leggermente distorta; ha dato un peso maggiore alla ricerca testuale e le ha dato più significato nei risultati finali.

Gli algoritmi basati sulla distanza come K-Nearest Neighbours (KNN) calcolano le distanze tra i punti dati, mentre BM25 si basa sulle frequenze delle occorrenze delle parole chiave. Entrambi restituiscono punteggi su scale completamente diverse. Ciò può portare a risultati distorti e classifiche imprecise. La nostra procedura di normalizzazione ha sempre prodotto un punteggio perfetto (1) per almeno un documento nel set di risultati della ricerca lessicale, quindi nella nostra situazione i risultati erano sbilanciati a favore della ricerca lessicale.
Per affrontare questo problema, esploriamo due funzioni comunemente utilizzate: normalizzazione Min-Max e normalizzazione Z-Score. Il metodo Z-Score ridimensiona i dati per ottenere una media e una varianza unitaria pari a zero, mentre la normalizzazione Min-Max ridimensiona i dati per adattarli a un intervallo specifico.
L’idea chiave è che posso acquisire una conoscenza di base di come vengono distribuiti i punteggi per ciascun tipo di ricerca con query simili se calcolo in anticipo i parametri utilizzati in queste funzioni di normalizzazione e li applico durante la fase di normalizzazione. Le formule delle due funzioni sono:

Considerare la struttura del tuo indice può aiutarti a decidere quale scegliere poiché ognuno presenta vantaggi propri. Se i tuoi documenti sono più simili tra loro e i risultati top-k di una tipica query restituiscono documenti molto simili tra loro e raggruppati insieme all’interno dell’indice, come mostrato nel grafico seguente, Min-Max potrebbe essere un’opzione migliore .

Diagramma dell’autore

Tuttavia, il punteggio Z è più adatto se i risultati sono distribuiti in modo più uniforme e presentano alcune caratteristiche di una distribuzione normale, come mostrato nell’esempio seguente.

Diagramma dell’autore

Entrambi gli approcci richiedono la determinazione di determinati parametri; dobbiamo calcolare la media, la deviazione standard, il punteggio minimo e il punteggio massimo. Dobbiamo determinare questi valori separatamente per ciascun tipo di ricerca perché i risultati vettoriali e semantici hanno sistemi di punteggio diversi. Per farlo, eseguiamo 1000 query casuali, una ricerca vettoriale e una ricerca semantica. Se non hai domande, puoi utilizzare OpenSearch API di scorrimento per estrarre campi di testo da utilizzare come query da diverse parti dell’indice. Imposta k su un valore significativo, ad esempio k=1000, per comprendere meglio i rapporti all’interno del nostro intervallo di punteggio. Tuttavia, fare attenzione a non impostare k troppo alto poiché ciò potrebbe avere un impatto sulla funzione Min-Max. Calcola semplicemente i parametri necessari dopo aver raccolto tutti questi punteggi.

    # Lexical Search
text_scores = ()
for query in queries:
response = client.search(
index=INDEX_NAME,
body={
"query": {
"match": {
"caption": query
}
},
"size": 1000
}
)
scores = (hit('_score') for hit in response('hits')('hits'))
text_scores.append(scores)

# Vector search
vector_scores = ()
# Vectorize queries using SentenceTransformer
query_embeddings = model.encode(queries)
# Perform vector search
for query_embedding in query_embeddings:
request_body = {
"size": 1000,
"query": {
"script_score": {
"query": {
"match_all": {}
},
"script": {
"source": "knn_score",
"lang": "knn",
"params": {
"field": "caption_embedding",
"query_value": query_embedding.tolist(),
"space_type": "cosinesimil"
}
}
}
}
}
response = client.search(
index=INDEX_NAME,
body=request_body
)
scores = (hit('_score') for hit in response('hits')('hits'))
vector_scores.append(scores)

vector_score_mean = np.mean(vector_scores) # Calculate the mean
vector_score_std = np.std(vector_scores, ddof=1) # Calculate standard deviation
vector_score_min = np.min(vector_scores) # Calculate minimum score
vector_score_max = np.max(vector_scores) # Calculate maximum score

text_score_mean = np.mean(text_scores) # Calculate the mean
text_score_std = np.std(text_scores, ddof=1) # Calculate standard deviation
text_score_min = np.min(text_scores) # Calculate minimum score
text_score_max = np.max(text_scores) # Calculate maximum score

Il processo è mostrato nello schema seguente:

Diagramma dell’autore

Metti da parte i parametri che hai estratto per i risultati lessicali e vettoriali. Ciascun indice dovrà essere eseguito separatamente una volta. Infine, nella fase di normalizzazione, utilizzeremo questi parametri nel modo seguente:

Normalizzazione utilizzando la funzione Z-Score (diagramma dell’autore)

Fonte: towardsdatascience.com

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *