Panoramica sull'analizzatore
Nell'elaborazione del testo, un analizzatore è un componente cruciale che converte il testo grezzo in un formato strutturato e ricercabile. Ogni analizzatore è generalmente composto da due elementi fondamentali: tokenizer e filtro. Insieme, trasformano il testo in ingresso in token, li raffinano e li preparano per un'indicizzazione e un recupero efficienti.
Alimentati da Tantivy, gli analizzatori in Milvus sono configurati durante la creazione della raccolta, quando si aggiungono i campi VARCHAR
allo schema della raccolta. I token prodotti da un analizzatore possono essere usati per costruire un indice per la corrispondenza del testo o convertiti in embedding sparsi per la ricerca full text. Per ulteriori informazioni, fare riferimento a Corrispondenza del testo o Ricerca di testo completo.
L'uso degli analizzatori può influire sulle prestazioni.
Ricerca a testo completo: Per la ricerca full text, i canali DataNode e QueryNode consumano i dati più lentamente perché devono attendere il completamento della tokenizzazione. Di conseguenza, i dati appena ingeriti impiegano più tempo per diventare disponibili per la ricerca.
Corrispondenza di testo: Per la corrispondenza del testo, anche la creazione dell'indice è più lenta, poiché la tokenizzazione deve essere completata prima di poter costruire un indice.
Anatomia di un analizzatore
Un analizzatore in Milvus è composto esattamente da un tokenizer e da zero o più filtri.
Tokenizzatore: Il tokenizer spezza il testo in ingresso in unità discrete chiamate tokens. Questi token possono essere parole o frasi, a seconda del tipo di tokenizer.
Filtri: I filtri possono essere applicati ai token per affinarli ulteriormente, ad esempio rendendoli minuscoli o rimuovendo parole comuni.
Il flusso di lavoro seguente mostra come un analizzatore elabora il testo.
Tipi di analizzatori
Milvus offre due tipi di analizzatori per soddisfare le diverse esigenze di elaborazione del testo.
Analizzatore integrato: Si tratta di configurazioni predefinite che coprono le attività comuni di elaborazione del testo con una configurazione minima. Gli analizzatori integrati sono ideali per le ricerche generiche, poiché non richiedono una configurazione complessa.
Analizzatore personalizzato: Per i requisiti più avanzati, gli analizzatori personalizzati consentono di definire la propria configurazione specificando sia il tokenizer che zero o più filtri. Questo livello di personalizzazione è particolarmente utile per casi d'uso specializzati in cui è necessario un controllo preciso sull'elaborazione del testo.
Se si omettono le configurazioni dell'analizzatore durante la creazione della raccolta, Milvus utilizza l'analizzatore standard
per l'elaborazione del testo. Per maggiori dettagli, consultare Standard.
Analizzatore integrato
Gli analizzatori integrati in Milvus sono preconfigurati con tokenizer e filtri specifici, consentendo di utilizzarli immediatamente senza doverli definire personalmente. Ogni analizzatore integrato è un modello che include un tokenizer e dei filtri preimpostati, con parametri opzionali per la personalizzazione.
Per esempio, per usare l'analizzatore incorporato standard
, basta specificare il nome standard
come type
e includere facoltativamente configurazioni aggiuntive specifiche per questo tipo di analizzatore, come stop_words
.
analyzer_params = {
"type": "standard", # Uses the standard built-in analyzer
"stop_words": ["a", "an", "for"] # Defines a list of common words (stop words) to exclude from tokenization
}
Map<String, Object> analyzerParams = new HashMap<>();
analyzerParams.put("type", "standard");
analyzerParams.put("stop_words", Arrays.asList("a", "an", "for"));
const analyzer_params = {
"type": "standard", // Uses the standard built-in analyzer
"stop_words": ["a", "an", "for"] // Defines a list of common words (stop words) to exclude from tokenization
};
export analyzerParams='{
"type": "standard",
"stop_words": ["a", "an", "for"]
}'
La configurazione dell'analizzatore integrato standard
di cui sopra è equivalente alla configurazione di un analizzatore personalizzato con i seguenti parametri, dove le opzioni tokenizer
e filter
sono definite esplicitamente per ottenere la stessa funzionalità:
analyzer_params = {
"tokenizer": "standard",
"filter": [
"lowercase",
{
"type": "stop",
"stop_words": ["a", "an", "for"]
}
]
}
Map<String, Object> analyzerParams = new HashMap<>();
analyzerParams.put("tokenizer", "standard");
analyzerParams.put("filter",
Arrays.asList("lowercase",
new HashMap<String, Object>() {{
put("type", "stop");
put("stop_words", Arrays.asList("a", "an", "for"));
}}));
const analyzer_params = {
"tokenizer": "standard",
"filter": [
"lowercase",
{
"type": "stop",
"stop_words": ["a", "an", "for"]
}
]
};
export analyzerParams='{
"type": "standard",
"filter": [
"lowercase",
{
"type": "stop",
"stop_words": ["a", "an", "for"]
}
]
}'
Milvus offre i seguenti analizzatori integrati, ognuno dei quali può essere usato direttamente specificando il loro nome come parametro type
.
standard
: Adatto per l'elaborazione di testi generici, applicando la tokenizzazione standard e il filtraggio delle minuscole.english
: Ottimizzato per i testi in lingua inglese, con supporto per le stop words inglesi.chinese
: Specializzato per l'elaborazione del testo cinese, con tokenizzazione adattata alle strutture della lingua cinese.
Analizzatore personalizzato
Per un'elaborazione del testo più avanzata, gli analizzatori personalizzati di Milvus consentono di costruire una pipeline di trattamento del testo su misura, specificando sia un tokenizzatore che dei filtri. Questa configurazione è ideale per casi d'uso specializzati in cui è richiesto un controllo preciso.
Tokenizzatore
Il tokenizer è un componente obbligatorio per un analizzatore personalizzato, che avvia la pipeline di analisi scomponendo il testo in ingresso in unità discrete o token. La tokenizzazione segue regole specifiche, come la divisione per spazi bianchi o punteggiatura, a seconda del tipo di tokenizzatore. Questo processo consente una gestione più precisa e indipendente di ogni parola o frase.
Ad esempio, un tokenizer converte il testo "Vector Database Built for Scale"
in token separati.
["Vector", "Database", "Built", "for", "Scale"]
Esempio di specificazione di un tokenizer.
analyzer_params = {
"tokenizer": "whitespace",
}
Map<String, Object> analyzerParams = new HashMap<>();
analyzerParams.put("tokenizer", "whitespace");
const analyzer_params = {
"tokenizer": "whitespace",
};
export analyzerParams='{
"type": "whitespace"
}'
Filtro
I filtri sono componenti opzionali che lavorano sui token prodotti dal tokenizer, trasformandoli o raffinandoli secondo le necessità. Ad esempio, dopo aver applicato un filtro lowercase
ai termini tokenizzati ["Vector", "Database", "Built", "for", "Scale"]
, il risultato potrebbe essere.
["vector", "database", "built", "for", "scale"]
I filtri di un analizzatore personalizzato possono essere integrati o personalizzati, a seconda delle esigenze di configurazione.
Filtri integrati: Preconfigurati da Milvus, richiedono una configurazione minima. È possibile utilizzare questi filtri immediatamente, specificando i loro nomi. I filtri seguenti sono integrati per l'uso diretto.
lowercase
: Converte il testo in minuscolo, garantendo una corrispondenza senza distinzione tra maiuscole e minuscole. Per maggiori dettagli, consultare Minuscole.asciifolding
: Converte i caratteri non ASCII in equivalenti ASCII, semplificando la gestione del testo multilingue. Per ulteriori informazioni, consultare la sezione Piegatura ASCII.alphanumonly
: Conserva solo i caratteri alfanumerici eliminando gli altri. Per maggiori dettagli, vedere Solo alfanumerici.cnalphanumonly
: Rimuove i token che contengono caratteri diversi da quelli cinesi, lettere inglesi o cifre. Per i dettagli, fare riferimento a Cnalphanumonly.cncharonly
: Rimuove i token che contengono caratteri non cinesi. Per i dettagli, fare riferimento a Cncharonly.
Esempio di utilizzo di un filtro integrato:
analyzer_params = { "tokenizer": "standard", # Mandatory: Specifies tokenizer "filter": ["lowercase"], # Optional: Built-in filter that converts text to lowercase }
Map<String, Object> analyzerParams = new HashMap<>(); analyzerParams.put("tokenizer", "standard"); analyzerParams.put("filter", Collections.singletonList("lowercase"));
const analyzer_params = { "tokenizer": "standard", // Mandatory: Specifies tokenizer "filter": ["lowercase"], // Optional: Built-in filter that converts text to lowercase }
export analyzerParams='{ "type": "standard", "filter": ["lowercase"] }'
Filtri personalizzati: I filtri personalizzati consentono configurazioni specifiche. È possibile definire un filtro personalizzato scegliendo un tipo di filtro valido (
filter.type
) e aggiungendo impostazioni specifiche per ogni tipo di filtro. Esempi di tipi di filtro che supportano la personalizzazione.stop
: Rimuove le parole comuni specificate impostando un elenco di parole di arresto (ad esempio,"stop_words": ["of", "to"]
). Per i dettagli, fare riferimento a Stop.length
: Esclude i token in base a criteri di lunghezza, come l'impostazione di una lunghezza massima dei token. Per i dettagli, vedere Lunghezza.stemmer
: Riduce le parole alla loro forma radicale per una corrispondenza più flessibile. Per ulteriori informazioni, vedere Stemmer.
Esempio di configurazione di un filtro personalizzato:
analyzer_params = { "tokenizer": "standard", # Mandatory: Specifies tokenizer "filter": [ { "type": "stop", # Specifies 'stop' as the filter type "stop_words": ["of", "to"], # Customizes stop words for this filter type } ] }
Map<String, Object> analyzerParams = new HashMap<>(); analyzerParams.put("tokenizer", "standard"); analyzerParams.put("filter", Collections.singletonList(new HashMap<String, Object>() {{ put("type", "stop"); put("stop_words", Arrays.asList("a", "an", "for")); }}));
const analyzer_params = { "tokenizer": "standard", // Mandatory: Specifies tokenizer "filter": [ { "type": "stop", // Specifies 'stop' as the filter type "stop_words": ["of", "to"], // Customizes stop words for this filter type } ] };
export analyzerParams='{ "type": "standard", "filter": [ { "type": "stop", "stop_words": ["a", "an", "for"] } ] }'
Esempio di utilizzo
In questo esempio, definiamo uno schema di raccolta con un campo vettoriale per le incorporazioni e due campi VARCHAR
per le funzionalità di elaborazione del testo. Ogni campo VARCHAR
è configurato con le proprie impostazioni di analisi per gestire le diverse esigenze di elaborazione.
from pymilvus import MilvusClient, DataType
# Set up a Milvus client
client = MilvusClient(
uri="http://localhost:19530"
)
# Create schema
schema = client.create_schema(auto_id=True, enable_dynamic_field=False)
# Add fields to schema
# Use a built-in analyzer
analyzer_params_built_in = {
"type": "english"
}
# Add VARCHAR field `title_en`
schema.add_field(
field_name='title_en',
datatype=DataType.VARCHAR,
max_length=1000,
enable_analyzer=True,
analyzer_params=analyzer_params_built_in,
enable_match=True,
)
# Configure a custom analyzer
analyzer_params_custom = {
"tokenizer": "standard",
"filter": [
"lowercase", # Built-in filter
{
"type": "length", # Custom filter
"max": 40
},
{
"type": "stop", # Custom filter
"stop_words": ["of", "to"]
}
]
}
# Add VARCHAR field `title`
schema.add_field(
field_name='title',
datatype=DataType.VARCHAR,
max_length=1000,
enable_analyzer=True,
analyzer_params=analyzer_params_custom,
enable_match=True,
)
# Add vector field
schema.add_field(field_name="embedding", datatype=DataType.FLOAT_VECTOR, dim=3)
# Add primary field
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
# Set up index params for vector field
index_params = client.prepare_index_params()
index_params.add_index(field_name="embedding", metric_type="COSINE", index_type="AUTOINDEX")
# Create collection with defined schema
client.create_collection(
collection_name="YOUR_COLLECTION_NAME",
schema=schema,
index_params=index_params
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
import io.milvus.v2.common.IndexParam;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
// Set up a Milvus client
ConnectConfig config = ConnectConfig.builder()
.uri("http://localhost:19530")
.build();
MilvusClientV2 client = new MilvusClientV2(config);
// Create schema
CreateCollectionReq.CollectionSchema schema = CreateCollectionReq.CollectionSchema.builder()
.enableDynamicField(false)
.build();
// Add fields to schema
// Use a built-in analyzer
Map<String, Object> analyzerParamsBuiltin = new HashMap<>();
analyzerParamsBuiltin.put("type", "english");
// Add VARCHAR field `title_en`
schema.addField(AddFieldReq.builder()
.fieldName("title_en")
.dataType(DataType.VarChar)
.maxLength(1000)
.enableAnalyzer(true)
.analyzerParams(analyzerParamsBuiltin)
.enableMatch(true)
.build());
// Configure a custom analyzer
Map<String, Object> analyzerParams = new HashMap<>();
analyzerParams.put("tokenizer", "standard");
analyzerParams.put("filter",
Arrays.asList("lowercase",
new HashMap<String, Object>() {{
put("type", "length");
put("max", 40);
}},
new HashMap<String, Object>() {{
put("type", "stop");
put("stop_words", Arrays.asList("a", "an", "for"));
}}
)
);
schema.addField(AddFieldReq.builder()
.fieldName("title")
.dataType(DataType.VarChar)
.maxLength(1000)
.enableAnalyzer(true)
.analyzerParams(analyzerParams)
.enableMatch(true) // must enable this if you use TextMatch
.build());
// Add vector field
schema.addField(AddFieldReq.builder()
.fieldName("embedding")
.dataType(DataType.FloatVector)
.dimension(3)
.build());
// Add primary field
schema.addField(AddFieldReq.builder()
.fieldName("id")
.dataType(DataType.Int64)
.isPrimaryKey(true)
.autoID(true)
.build());
// Set up index params for vector field
List<IndexParam> indexes = new ArrayList<>();
indexes.add(IndexParam.builder()
.fieldName("embedding")
.indexType(IndexParam.IndexType.AUTOINDEX)
.metricType(IndexParam.MetricType.COSINE)
.build());
// Create collection with defined schema
CreateCollectionReq requestCreate = CreateCollectionReq.builder()
.collectionName("YOUR_COLLECTION_NAME")
.collectionSchema(schema)
.indexParams(indexes)
.build();
client.createCollection(requestCreate);
import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";
// Set up a Milvus client
const client = new MilvusClient("http://localhost:19530");
// Use a built-in analyzer for VARCHAR field `title_en`
const analyzerParamsBuiltIn = {
type: "english",
};
// Configure a custom analyzer for VARCHAR field `title`
const analyzerParamsCustom = {
tokenizer: "standard",
filter: [
"lowercase",
{
type: "length",
max: 40,
},
{
type: "stop",
stop_words: ["of", "to"],
},
],
};
// Create schema
const schema = {
auto_id: true,
fields: [
{
name: "id",
type: DataType.INT64,
is_primary: true,
},
{
name: "title_en",
data_type: DataType.VARCHAR,
max_length: 1000,
enable_analyzer: true,
analyzer_params: analyzerParamsBuiltIn,
enable_match: true,
},
{
name: "title",
data_type: DataType.VARCHAR,
max_length: 1000,
enable_analyzer: true,
analyzer_params: analyzerParamsCustom,
enable_match: true,
},
{
name: "embedding",
data_type: DataType.FLOAT_VECTOR,
dim: 4,
},
],
};
// Set up index params for vector field
const indexParams = [
{
name: "embedding",
metric_type: "COSINE",
index_type: "AUTOINDEX",
},
];
// Create collection with defined schema
await client.createCollection({
collection_name: "YOUR_COLLECTION_NAME",
schema: schema,
index_params: indexParams,
});
console.log("Collection created successfully!");
export schema='{
"autoId": true,
"enabledDynamicField": false,
"fields": [
{
"fieldName": "id",
"dataType": "Int64",
"isPrimary": true
},
{
"fieldName": "title_en",
"dataType": "VarChar",
"elementTypeParams": {
"max_length": 1000,
"enable_analyzer": true,
"enable_match": true,
"analyzer_params": {"type": "english"}
}
},
{
"fieldName": "title",
"dataType": "VarChar",
"elementTypeParams": {
"max_length": 1000,
"enable_analyzer": true,
"enable_match": true,
"analyzer_params": {
"tokenizer": "standard",
"filter":[
"lowercase",
{
"type":"length",
"max":40
},
{
"type":"stop",
"stop_words":["of","to"]
}
]
}
}
},
{
"fieldName": "embedding",
"dataType": "FloatVector",
"elementTypeParams": {
"dim":3
}
}
]
}'
export indexParams='[
{
"fieldName": "embedding",
"metricType": "COSINE",
"indexType": "AUTOINDEX"
}
]'
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\": \"YOUR_COLLECTION_NAME\",
\"schema\": $schema,
\"indexParams\": $indexParams
}"