Corrispondenza del testo
La corrispondenza del testo in Milvus consente di recuperare documenti precisi in base a termini specifici. Questa funzione è utilizzata principalmente per la ricerca filtrata per soddisfare condizioni specifiche e può incorporare un filtro scalare per affinare i risultati della query, consentendo ricerche di similarità all'interno di vettori che soddisfano criteri scalari.
La corrispondenza del testo si concentra sulla ricerca delle occorrenze esatte dei termini della query, senza assegnare un punteggio alla rilevanza dei documenti abbinati. Se si desidera recuperare i documenti più rilevanti in base al significato semantico e all'importanza dei termini della query, si consiglia di utilizzare la ricerca full text.
Panoramica
Milvus integra Tantivy per alimentare l'indice inverso e la ricerca testuale basata sui termini. Per ogni inserimento di testo, Milvus lo indicizza seguendo la procedura.
Analizzatore: L'analizzatore elabora il testo in ingresso tokenizzandolo in singole parole, o token, e applicando poi i filtri necessari. Ciò consente a Milvus di costruire un indice basato su questi token.
Indicizzazione: Dopo l'analisi del testo, Milvus crea un indice inverso che mappa ogni singolo token con i documenti che lo contengono.
Quando un utente esegue una corrispondenza di testo, l'indice invertito viene utilizzato per recuperare rapidamente tutti i documenti che contengono i termini. Questo è molto più veloce della scansione di ogni singolo documento.
Corrispondenza di testo
Abilita la corrispondenza del testo
La corrispondenza testuale funziona con il tipo di campo VARCHAR
, che è essenzialmente il tipo di dati stringa di Milvus. Per abilitare la corrispondenza al testo, impostare sia enable_analyzer
che enable_match
su True
e poi configurare facoltativamente un analizzatore per l'analisi del testo quando si definisce lo schema della raccolta.
Impostare enable_analyzer
e enable_match
Per abilitare la corrispondenza al testo per un campo specifico VARCHAR
, impostare entrambi i parametri enable_analyzer
e enable_match
su True
quando si definisce lo schema del campo. In questo modo Milvus viene istruito a tokenizzare il testo e a creare un indice invertito per il campo specificato, consentendo corrispondenze di testo rapide ed efficienti.
from pymilvus import MilvusClient, DataType
schema = MilvusClient.create_schema(auto_id=True, enable_dynamic_field=False)
schema.add_field(
field_name='text',
datatype=DataType.VARCHAR,
max_length=1000,
enable_analyzer=True, # Whether to enable text analysis for this field
enable_match=True # Whether to enable text match
)
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()
.enableDynamicField(false)
.build();
schema.addField(AddFieldReq.builder()
.fieldName("text")
.dataType(DataType.VarChar)
.maxLength(1000)
.enableAnalyzer(true)
.enableMatch(true)
.build());
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,
},
];
export schema='{
"autoId": true,
"enabledDynamicField": false,
"fields": [
{
"fieldName": "id",
"dataType": "Int64",
"isPrimary": true
},
{
"fieldName": "text",
"dataType": "VarChar",
"elementTypeParams": {
"max_length": 1000,
"enable_analyzer": true,
"enable_match": true
}
},
{
"fieldName": "sparse",
"dataType": "SparseFloatVector"
}
]
}'
Opzionale: Configurare un analizzatore
Le prestazioni e l'accuratezza della corrispondenza del testo dipendono dall'analizzatore selezionato. Diversi analizzatori sono adatti a varie lingue e strutture di testo, quindi la scelta di quello giusto può avere un impatto significativo sui risultati della ricerca per il vostro caso d'uso specifico.
Per impostazione predefinita, Milvus utilizza l'analizzatore standard
, che tokenizza il testo in base agli spazi bianchi e alla punteggiatura, rimuove i token più lunghi di 40 caratteri e converte il testo in minuscolo. Non sono necessari parametri aggiuntivi per applicare questa impostazione predefinita. Per ulteriori informazioni, consultare Standard.
Nei casi in cui sia necessario un analizzatore diverso, è possibile configurarne uno utilizzando il parametro analyzer_params
. Ad esempio, per applicare l'analizzatore english
per l'elaborazione del testo inglese.
analyzer_params={
"type": "english"
}
schema.add_field(
field_name='text',
datatype=DataType.VARCHAR,
max_length=200,
enable_analyzer=True,
analyzer_params=analyzer_params,
enable_match=True,
)
Map<String, Object> analyzerParams = new HashMap<>();
analyzerParams.put("type", "english");
schema.addField(AddFieldReq.builder()
.fieldName("text")
.dataType(DataType.VarChar)
.maxLength(200)
.enableAnalyzer(true)
.analyzerParams(analyzerParams)
.enableMatch(true)
.build());
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,
analyzer_params: { type: 'english' },
},
{
name: "sparse",
data_type: DataType.SparseFloatVector,
},
];
export schema='{
"autoId": true,
"enabledDynamicField": false,
"fields": [
{
"fieldName": "id",
"dataType": "Int64",
"isPrimary": true
},
{
"fieldName": "text",
"dataType": "VarChar",
"elementTypeParams": {
"max_length": 200,
"enable_analyzer": true,
"enable_match": true,
"analyzer_params": {"type": "english"}
}
},
{
"fieldName": "my_vector",
"dataType": "FloatVector",
"elementTypeParams": {
"dim": "5"
}
}
]
}'
Milvus offre anche altri analizzatori adatti a diversi linguaggi e scenari. Per maggiori dettagli, consultare la sezione Panoramica.
Utilizzare la corrispondenza del testo
Una volta abilitata la corrispondenza del testo per un campo VARCHAR nello schema della raccolta, è possibile eseguire corrispondenze di testo utilizzando l'espressione TEXT_MATCH
.
Sintassi dell'espressione TEXT_MATCH
L'espressione TEXT_MATCH
è usata per specificare il campo e i termini da cercare. La sua sintassi è la seguente.
TEXT_MATCH(field_name, text)
field_name
: Il nome del campo VARCHAR da cercare.text
: I termini da cercare. I termini multipli possono essere separati da spazi o da altri delimitatori appropriati in base alla lingua e all'analizzatore configurato.
Per impostazione predefinita, TEXT_MATCH
utilizza la logica di corrispondenza OR, ovvero restituisce i documenti che contengono uno qualsiasi dei termini specificati. Ad esempio, per cercare documenti contenenti il termine machine
o deep
nel campo text
, utilizzare la seguente espressione.
filter = "TEXT_MATCH(text, 'machine deep')"
String filter = "TEXT_MATCH(text, 'machine deep')";
const filter = "TEXT_MATCH(text, 'machine deep')";
export filter="\"TEXT_MATCH(text, 'machine deep')\""
È inoltre possibile combinare più espressioni TEXT_MATCH
utilizzando gli operatori logici per eseguire la corrispondenza AND. Ad esempio, per cercare documenti contenenti sia machine
che deep
nel campo text
, utilizzare la seguente espressione.
filter = "TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'deep')"
String filter = "TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'deep')";
const filter = "TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'deep')"
export filter="\"TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'deep')\""
Ricerca con corrispondenza di testo
La corrispondenza del testo può essere utilizzata in combinazione con la ricerca per similarità vettoriale per restringere l'ambito di ricerca e migliorare le prestazioni della ricerca. Filtrando la raccolta con la corrispondenza del testo prima della ricerca per similarità vettoriale, è possibile ridurre il numero di documenti da ricercare, con conseguenti tempi di interrogazione più rapidi.
In questo esempio, l'espressione filter
filtra i risultati della ricerca per includere solo i documenti che corrispondono al termine specificato keyword1
o keyword2
. La ricerca di similarità vettoriale viene quindi eseguita su questo sottoinsieme di documenti filtrati.
# Match entities with `keyword1` or `keyword2`
filter = "TEXT_MATCH(text, 'keyword1 keyword2')"
# Assuming 'embeddings' is the vector field and 'text' is the VARCHAR field
result = MilvusClient.search(
collection_name="YOUR_COLLECTION_NAME", # Your collection name
anns_field="embeddings", # Vector field name
data=[query_vector], # Query vector
filter=filter,
search_params={"params": {"nprobe": 10}},
limit=10, # Max. number of results to return
output_fields=["id", "text"] # Fields to return
)
String filter = "TEXT_MATCH(text, 'keyword1 keyword2')";
SearchResp searchResp = client.search(SearchReq.builder()
.collectionName("YOUR_COLLECTION_NAME")
.annsField("embeddings")
.data(Collections.singletonList(queryVector)))
.filter(filter)
.topK(10)
.outputFields(Arrays.asList("id", "text"))
.build());
// Match entities with `keyword1` or `keyword2`
const filter = "TEXT_MATCH(text, 'keyword1 keyword2')";
// Assuming 'embeddings' is the vector field and 'text' is the VARCHAR field
const result = await client.search(
collection_name: "YOUR_COLLECTION_NAME", // Your collection name
anns_field: "embeddings", // Vector field name
data: [query_vector], // Query vector
filter: filter,
params: {"nprobe": 10},
limit: 10, // Max. number of results to return
output_fields: ["id", "text"] //Fields to return
);
export filter="\"TEXT_MATCH(text, 'keyword1 keyword2')\""
export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "demo2",
"annsField": "my_vector",
"data": [[0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104]],
"filter": '"$filter"',
"searchParams": {
"params": {
"nprobe": 10
}
},
"limit": 3,
"outputFields": ["text","id"]
}'
Query con corrispondenza di testo
La corrispondenza testuale può essere utilizzata anche per il filtraggio scalare nelle operazioni di query. Specificando un'espressione TEXT_MATCH
nel parametro expr
del metodo query()
, è possibile recuperare i documenti che corrispondono ai termini indicati.
L'esempio seguente recupera i documenti in cui il campo text
contiene entrambi i termini keyword1
e keyword2
.
# Match entities with both `keyword1` and `keyword2`
filter = "TEXT_MATCH(text, 'keyword1') and TEXT_MATCH(text, 'keyword2')"
result = MilvusClient.query(
collection_name="YOUR_COLLECTION_NAME",
filter=filter,
output_fields=["id", "text"]
)
String filter = "TEXT_MATCH(text, 'keyword1') and TEXT_MATCH(text, 'keyword2')";
QueryResp queryResp = client.query(QueryReq.builder()
.collectionName("YOUR_COLLECTION_NAME")
.filter(filter)
.outputFields(Arrays.asList("id", "text"))
.build()
);
// Match entities with both `keyword1` and `keyword2`
const filter = "TEXT_MATCH(text, 'keyword1') and TEXT_MATCH(text, 'keyword2')";
const result = await client.query(
collection_name: "YOUR_COLLECTION_NAME",
filter: filter,
output_fields: ["id", "text"]
)
export filter="\"TEXT_MATCH(text, 'keyword1') and TEXT_MATCH(text, 'keyword2')\""
export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/query" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "demo2",
"filter": '"$filter"',
"outputFields": ["id", "text"]
}'
Considerazioni
L'abilitazione della corrispondenza del testo per un campo attiva la creazione di un indice invertito, che consuma risorse di memorizzazione. Considerare l'impatto sullo storage quando si decide di abilitare questa funzione, poiché varia in base alla dimensione del testo, ai token unici e all'analizzatore utilizzato.
Una volta definito un analizzatore nello schema, le sue impostazioni diventano permanenti per quella raccolta. Se si decide che un analizzatore diverso è più adatto alle proprie esigenze, si può decidere di abbandonare la raccolta esistente e crearne una nuova con la configurazione dell'analizzatore desiderato.