Обзор анализаторов
В обработке текстов анализатор - это важнейший компонент, преобразующий необработанный текст в структурированный, пригодный для поиска формат. Каждый анализатор обычно состоит из двух основных элементов: токенизатора и фильтра. Вместе они преобразуют входной текст в лексемы, уточняют эти лексемы и готовят их к эффективному индексированию и поиску.
Анализаторы в Milvus, работающие на базе Tantivy, настраиваются во время создания коллекции, когда вы добавляете поля VARCHAR
в схему коллекции. Токены, созданные анализатором, могут быть использованы для построения индекса для сопоставления с текстом или преобразованы в разреженные вкрапления для полнотекстового поиска. Дополнительные сведения см. в разделе "Текстовое соответствие или полнотекстовый поиск".
Использование анализаторов может повлиять на производительность.
Полнотекстовый поиск: При полнотекстовом поиске каналы DataNode и QueryNode потребляют данные медленнее, поскольку им приходится ждать завершения токенизации. В результате вновь поступившие данные становятся доступными для поиска дольше.
Текстовое соответствие: При сопоставлении текстов создание индекса также происходит медленнее, поскольку перед созданием индекса необходимо завершить токенизацию.
Анатомия анализатора
Анализатор в Milvus состоит ровно из одного токенизатора и нуля или более фильтров.
Токенизатор: Токенизатор разбивает входной текст на дискретные единицы, называемые лексемами. Эти лексемы могут быть словами или фразами, в зависимости от типа токенизатора.
Фильтры: Фильтры могут применяться к лексемам для их дальнейшего уточнения, например, для перевода их в нижний регистр или удаления общих слов.
Токенизаторы поддерживают только формат UTF-8. Поддержка других форматов будет добавлена в будущих релизах.
Приведенный ниже рабочий процесс показывает, как анализатор обрабатывает текст.
Типы анализаторов
Milvus предоставляет два типа анализаторов для удовлетворения различных потребностей в обработке текста.
Встроенный анализатор: Это предопределенные конфигурации, которые решают общие задачи обработки текста с минимальной настройкой. Встроенные анализаторы идеально подходят для поиска общего назначения, поскольку не требуют сложной настройки.
Пользовательский анализатор: Для более сложных задач пользовательские анализаторы позволяют задать собственную конфигурацию, указав как токенизатор, так и ноль или более фильтров. Такой уровень настройки особенно полезен в специализированных случаях, когда требуется точный контроль над обработкой текста.
Если вы не указываете конфигурацию анализатора при создании коллекции, Milvus по умолчанию использует анализатор standard
для обработки всего текста. Подробнее см. в разделе Стандартный.
Встроенный анализатор
Встроенные анализаторы в Milvus предварительно сконфигурированы с определенными токенизаторами и фильтрами, что позволяет использовать их сразу, без необходимости определять эти компоненты самостоятельно. Каждый встроенный анализатор представляет собой шаблон, включающий в себя предустановленные токенизаторы и фильтры, с дополнительными параметрами для настройки.
Например, чтобы использовать встроенный анализатор standard
, достаточно указать его имя standard
в качестве type
и опционально включить дополнительные конфигурации, специфичные для этого типа анализатора, например 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"]
}'
Приведенная выше конфигурация встроенного анализатора standard
эквивалентна настройке пользовательского анализатора со следующими параметрами, где опции tokenizer
и filter
явно определены для достижения той же функциональности:
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 предлагает следующие встроенные анализаторы, каждый из которых можно использовать напрямую, указав его имя в качестве параметра type
.
standard
: : Подходит для обработки текста общего назначения, применяя стандартную токенизацию и фильтрацию строчных букв.english
: : Оптимизирован для англоязычного текста, с поддержкой английских стоп-слов.chinese
: Специализирован для обработки китайского текста, включая токенизацию, адаптированную к структурам китайского языка.
Пользовательский анализатор
Для более сложной обработки текста пользовательские анализаторы в Milvus позволяют создать индивидуальный конвейер обработки текста, указав токенизатор и фильтры. Такая настройка идеально подходит для специализированных случаев, когда требуется точный контроль.
Токенизатор
Токенизатор - это обязательный компонент пользовательского анализатора, который запускает конвейер анализатора, разбивая входной текст на дискретные единицы или токены. В зависимости от типа токенизатора токенизация выполняется по определенным правилам, таким как разбиение на пробельные символы или знаки препинания. Этот процесс позволяет более точно и независимо обрабатывать каждое слово или фразу.
Например, токенизатор преобразует текст "Vector Database Built for Scale"
в отдельные лексемы.
["Vector", "Database", "Built", "for", "Scale"]
Пример указания токенизатора.
analyzer_params = {
"tokenizer": "whitespace",
}
Map<String, Object> analyzerParams = new HashMap<>();
analyzerParams.put("tokenizer", "whitespace");
const analyzer_params = {
"tokenizer": "whitespace",
};
export analyzerParams='{
"type": "whitespace"
}'
Фильтр
Фильтры - это необязательные компоненты, работающие с токенами, полученными токенизатором, преобразуя или уточняя их по мере необходимости. Например, после применения фильтра lowercase
к токенизированным терминам ["Vector", "Database", "Built", "for", "Scale"]
, результат может быть следующим.
["vector", "database", "built", "for", "scale"]
Фильтры в пользовательском анализаторе могут быть как встроенными, так и пользовательскими, в зависимости от потребностей конфигурации.
Встроенные фильтры: Предварительно сконфигурированы Milvus и требуют минимальной настройки. Вы можете использовать эти фильтры из коробки, указав их имена. Приведенные ниже фильтры являются встроенными для прямого использования.
lowercase
: Преобразует текст в нижний регистр, обеспечивая сопоставление без учета регистра. Подробнее см. в разделе Нижний регистр.asciifolding
: Преобразует не ASCII-символы в ASCII-эквиваленты, упрощая работу с многоязычным текстом. Подробнее см. в разделе Сложение ASCII.alphanumonly
: Сохраняет только алфавитно-цифровые символы, удаляя остальные. Подробнее см. в разделе "Только алфавитно-цифровые".cnalphanumonly
: Удаляет лексемы, содержащие любые символы, кроме китайских, английских букв или цифр. Подробнее см. в разделе Cnalphanumonly.cncharonly
: Удаляет маркеры, содержащие любые некитайские символы. Подробнее см. в разделе Cncharonly.
Пример использования встроенного фильтра:
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"] }'
Пользовательские фильтры: Пользовательские фильтры позволяют создавать специализированные конфигурации. Вы можете определить пользовательский фильтр, выбрав подходящий тип фильтра (
filter.type
) и добавив специальные настройки для каждого типа фильтра. Примеры типов фильтров, поддерживающих настройку.stop
: Удаляет указанные общие слова, задавая список стоп-слов (например,"stop_words": ["of", "to"]
). Подробнее см. в разделе "Стоп-слова".length
: Исключает лексемы на основе критериев длины, например, задавая максимальную длину лексемы. Подробнее см. в разделе Длина.stemmer
: Сокращает слова до их корневых форм для более гибкого подбора. Подробнее см. в разделе Стеммер.
Пример настройки пользовательского фильтра:
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"] } ] }'
Пример использования
В этом примере мы определяем схему коллекции с векторным полем для вкраплений и двумя полями VARCHAR
для возможностей обработки текста. Каждое поле VARCHAR
имеет собственные настройки анализатора для обработки различных данных.
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
}"