Ricerca a testo completo
La ricerca full text è una funzione che recupera i documenti contenenti termini o frasi specifiche nei dataset di testo, classificando poi i risultati in base alla rilevanza. Questa funzione supera le limitazioni della ricerca semantica, che potrebbe trascurare termini precisi, garantendo la ricezione di risultati più accurati e contestualmente rilevanti. Inoltre, semplifica le ricerche vettoriali accettando input di testo grezzo, convertendo automaticamente i dati testuali in embedding sparsi senza dover generare manualmente embedding vettoriali.
Utilizzando l'algoritmo BM25 per il punteggio di rilevanza, questa funzione è particolarmente preziosa negli scenari di retrieval-augmented generation (RAG), dove dà priorità ai documenti che corrispondono strettamente a termini di ricerca specifici.
Integrando la ricerca full text con la ricerca vettoriale densa basata sulla semantica, è possibile migliorare l'accuratezza e la pertinenza dei risultati della ricerca. Per ulteriori informazioni, consultare la sezione Ricerca ibrida.
La ricerca full text è disponibile in Milvus Standalone e Milvus Distributed ma non in Milvus Lite, anche se l'aggiunta a Milvus Lite è in programma.
Panoramica
La ricerca full text semplifica il processo di ricerca basato sul testo eliminando la necessità di incorporazione manuale. Questa funzione funziona attraverso il seguente flusso di lavoro.
Inserimento del testo: L'utente inserisce documenti di testo grezzi o fornisce un testo di query senza necessità di incorporazione manuale.
Analisi del testo: Milvus utilizza un analizzatore per tokenizzare il testo in ingresso in singoli termini ricercabili. Per ulteriori informazioni sugli analizzatori, consultare la sezione Panoramica degli analizzatori.
Elaborazione della funzione: La funzione incorporata riceve i termini tokenizzati e li converte in rappresentazioni vettoriali rade.
Memorizzazione delle collezioni: Milvus memorizza queste rappresentazioni rade in una raccolta per un recupero efficiente.
Punteggio BM25: Durante la ricerca, Milvus applica l'algoritmo BM25 per calcolare i punteggi dei documenti memorizzati e classifica i risultati corrispondenti in base alla pertinenza con il testo dell'interrogazione.
Ricerca a testo completo
Per utilizzare la ricerca full text, seguire i seguenti passaggi principali.
Creare una raccolta: Impostare una raccolta con i campi necessari e definire una funzione per convertire il testo grezzo in embedding sparsi.
Inserire i dati: Inserire i documenti di testo grezzo nella raccolta.
Eseguire ricerche: Utilizzare testi di interrogazione per cercare nella raccolta e recuperare i risultati pertinenti.
Creare una raccolta per la ricerca full text
Per abilitare la ricerca full text, creare una raccolta con uno schema specifico. Questo schema deve includere tre campi necessari.
Il campo primario che identifica in modo univoco ogni entità della raccolta.
Un campo
VARCHAR
che memorizza documenti di testo grezzo, con l'attributoenable_analyzer
impostato suTrue
. Questo permette a Milvus di tokenizzare il testo in termini specifici per l'elaborazione delle funzioni.Un campo
SPARSE_FLOAT_VECTOR
riservato alla memorizzazione di incorporazioni rade che Milvus genererà automaticamente per il campoVARCHAR
.
Definire lo schema della raccolta
Per prima cosa, creare lo schema e aggiungere i campi necessari.
from pymilvus import MilvusClient, DataType, Function, FunctionType
client = MilvusClient(uri="http://localhost:19530")
schema = client.create_schema()
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True, auto_id=True)
schema.add_field(field_name="text", datatype=DataType.VARCHAR, max_length=1000, enable_analyzer=True)
schema.add_field(field_name="sparse", datatype=DataType.SPARSE_FLOAT_VECTOR)
import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
CreateCollectionReq.CollectionSchema schema = CreateCollectionReq.CollectionSchema.builder()
.build();
schema.addField(AddFieldReq.builder()
.fieldName("id")
.dataType(DataType.Int64)
.isPrimaryKey(true)
.autoID(true)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("text")
.dataType(DataType.VarChar)
.maxLength(1000)
.enableAnalyzer(true)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("sparse")
.dataType(DataType.SparseFloatVector)
.build());
import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";
const address = "http://localhost:19530";
const token = "root:Milvus";
const client = new MilvusClient({address, token});
const schema = [
{
name: "id",
data_type: DataType.Int64,
is_primary_key: true,
},
{
name: "text",
data_type: "VarChar",
enable_analyzer: true,
enable_match: true,
max_length: 1000,
},
{
name: "sparse",
data_type: DataType.SparseFloatVector,
},
];
console.log(res.results)
export schema='{
"autoId": true,
"enabledDynamicField": false,
"fields": [
{
"fieldName": "id",
"dataType": "Int64",
"isPrimary": true
},
{
"fieldName": "text",
"dataType": "VarChar",
"elementTypeParams": {
"max_length": 1000,
"enable_analyzer": true
}
},
{
"fieldName": "sparse",
"dataType": "SparseFloatVector"
}
]
}'
In questa configurazione.
id
: serve come chiave primaria ed è generato automaticamente conauto_id=True
.text
: memorizza i dati di testo grezzo per le operazioni di ricerca full text. Il tipo di dati deve essereVARCHAR
, poichéVARCHAR
è il tipo di dati stringa di Milvus per la memorizzazione del testo. Impostareenable_analyzer=True
per consentire a Milvus di tokenizzare il testo. Per impostazione predefinita, Milvus utilizza l'analizzatore standard per l'analisi del testo. Per configurare un analizzatore diverso, fare riferimento a Panoramica.sparse
: un campo vettoriale riservato per memorizzare le incorporazioni sparse generate internamente per le operazioni di ricerca full text. Il tipo di dati deve essereSPARSE_FLOAT_VECTOR
.
Ora, definire una funzione che converta il testo in rappresentazioni vettoriali rade e aggiungerla allo schema.
bm25_function = Function(
name="text_bm25_emb", # Function name
input_field_names=["text"], # Name of the VARCHAR field containing raw text data
output_field_names=["sparse"], # Name of the SPARSE_FLOAT_VECTOR field reserved to store generated embeddings
function_type=FunctionType.BM25,
)
schema.add_function(bm25_function)
import io.milvus.common.clientenum.FunctionType;
import io.milvus.v2.service.collection.request.CreateCollectionReq.Function;
import java.util.*;
schema.addFunction(Function.builder()
.functionType(FunctionType.BM25)
.name("text_bm25_emb")
.inputFieldNames(Collections.singletonList("text"))
.outputFieldNames(Collections.singletonList("vector"))
.build());
const functions = [
{
name: 'text_bm25_emb',
description: 'bm25 function',
type: FunctionType.BM25,
input_field_names: ['text'],
output_field_names: ['vector'],
params: {},
},
];
export schema='{
"autoId": true,
"enabledDynamicField": false,
"fields": [
{
"fieldName": "id",
"dataType": "Int64",
"isPrimary": true
},
{
"fieldName": "text",
"dataType": "VarChar",
"elementTypeParams": {
"max_length": 1000,
"enable_analyzer": true
}
},
{
"fieldName": "sparse",
"dataType": "SparseFloatVector"
}
],
"functions": [
{
"name": "text_bm25_emb",
"type": "BM25",
"inputFieldNames": ["text"],
"outputFieldNames": ["sparse"],
"params": {}
}
]
}'
Parametro | Descrizione |
---|---|
| Il nome della funzione. Questa funzione converte il testo grezzo dal campo |
| Il nome del campo |
| Il nome del campo in cui verranno memorizzati i vettori sparsi generati internamente. Per |
| Il tipo di funzione da utilizzare. Impostare il valore su |
Per collezioni con più campi VARCHAR
che richiedono la conversione da testo a vettore sparso, aggiungere funzioni separate allo schema della collezione, assicurandosi che ogni funzione abbia un nome e un valore output_field_names
unici.
Configurare l'indice
Dopo aver definito lo schema con i campi necessari e la funzione incorporata, configurare l'indice per la raccolta. Per semplificare questo processo, utilizzare AUTOINDEX
come index_type
, un'opzione che consente a Milvus di scegliere e configurare il tipo di indice più adatto in base alla struttura dei dati.
index_params = client.prepare_index_params()
index_params.add_index(
field_name="sparse",
index_type="AUTOINDEX",
metric_type="BM25"
)
import io.milvus.v2.common.IndexParam;
List<IndexParam> indexes = new ArrayList<>();
indexes.add(IndexParam.builder()
.fieldName("sparse")
.indexType(IndexParam.IndexType.SPARSE_INVERTED_INDEX)
.metricType(IndexParam.MetricType.BM25)
.build());
const index_params = [
{
field_name: "sparse",
metric_type: "BM25",
index_type: "AUTOINDEX",
},
];
export indexParams='[
{
"fieldName": "sparse",
"metricType": "BM25",
"indexType": "AUTOINDEX"
}
]'
Parametro | Descrizione |
---|---|
| Il nome del campo vettoriale da indicizzare. Per la ricerca full text, questo dovrebbe essere il campo che memorizza i vettori sparsi generati. In questo esempio, impostare il valore su |
| Il tipo di indice da creare. |
| Il valore di questo parametro deve essere impostato su |
Creare la collezione
Creare ora la collezione utilizzando i parametri dello schema e dell'indice definiti.
client.create_collection(
collection_name='demo',
schema=schema,
index_params=index_params
)
import io.milvus.v2.service.collection.request.CreateCollectionReq;
CreateCollectionReq requestCreate = CreateCollectionReq.builder()
.collectionName("demo")
.collectionSchema(schema)
.indexParams(indexes)
.build();
client.createCollection(requestCreate);
await client.create_collection(
collection_name: 'demo',
schema: schema,
index_params: index_params,
functions: functions
);
export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d "{
\"collectionName\": \"demo\",
\"schema\": $schema,
\"indexParams\": $indexParams
}"
Inserire i dati di testo
Dopo aver impostato la raccolta e l'indice, si è pronti per inserire i dati di testo. In questo processo, è sufficiente fornire il testo grezzo. La funzione integrata definita in precedenza genera automaticamente il vettore sparse corrispondente per ogni voce di testo.
client.insert('demo', [
{'text': 'information retrieval is a field of study.'},
{'text': 'information retrieval focuses on finding relevant information in large datasets.'},
{'text': 'data mining and information retrieval overlap in research.'},
])
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import io.milvus.v2.service.vector.request.InsertReq;
Gson gson = new Gson();
List<JsonObject> rows = Arrays.asList(
gson.fromJson("{\"text\": \"information retrieval is a field of study.\"}", JsonObject.class),
gson.fromJson("{\"text\": \"information retrieval focuses on finding relevant information in large datasets.\"}", JsonObject.class),
gson.fromJson("{\"text\": \"data mining and information retrieval overlap in research.\"}", JsonObject.class)
);
client.insert(InsertReq.builder()
.collectionName("demo")
.data(rows)
.build());
await client.insert({
collection_name: 'demo',
data: [
{'text': 'information retrieval is a field of study.'},
{'text': 'information retrieval focuses on finding relevant information in large datasets.'},
{'text': 'data mining and information retrieval overlap in research.'},
]);
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"data": [
{"text": "information retrieval is a field of study."},
{"text": "information retrieval focuses on finding relevant information in large datasets."},
{"text": "data mining and information retrieval overlap in research."}
],
"collectionName": "demo"
}'
Eseguire una ricerca full text
Una volta inseriti i dati nella raccolta, è possibile eseguire ricerche full text utilizzando query di testo grezzo. Milvus converte automaticamente la query in un vettore sparse e classifica i risultati della ricerca utilizzando l'algoritmo BM25, per poi restituire i risultati topK (limit
).
search_params = {
'params': {'drop_ratio_search': 0.2},
}
client.search(
collection_name='demo',
data=['whats the focus of information retrieval?'],
anns_field='sparse',
limit=3,
search_params=search_params
)
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.EmbeddedText;
import io.milvus.v2.service.vector.response.SearchResp;
Map<String,Object> searchParams = new HashMap<>();
searchParams.put("drop_ratio_search", 0.2);
SearchResp searchResp = client.search(SearchReq.builder()
.collectionName("demo")
.data(Collections.singletonList(new EmbeddedText("whats the focus of information retrieval?")))
.annsField("sparse")
.topK(3)
.searchParams(searchParams)
.outputFields(Collections.singletonList("text"))
.build());
await client.search(
collection_name: 'demo',
data: ['whats the focus of information retrieval?'],
anns_field: 'sparse',
limit: 3,
params: {'drop_ratio_search': 0.2},
)
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--data-raw '{
"collectionName": "demo",
"data": [
"whats the focus of information retrieval?"
],
"annsField": "sparse",
"limit": 3,
"outputFields": [
"text"
],
"searchParams":{
"params":{
"drop_ratio_search":0.2
}
}
}'
Parametro | Descrizione |
---|---|
| Un dizionario contenente i parametri di ricerca. |
| Percentuale di termini a bassa frequenza da ignorare durante la ricerca. Per i dettagli, fare riferimento a Vettore sparso. |
| Il testo grezzo della query. |
| Il nome del campo che contiene i vettori sparsi generati internamente. |
| Numero massimo di top match da restituire. |