分析器概述
在文本处理中,分析器是将原始文本转换为结构化可搜索格式的关键组件。每个分析器通常由两个核心部件组成:标记器和过滤器。它们共同将输入文本转换为标记,完善这些标记,并为高效索引和检索做好准备。
Milvus 中的分析器由Tantivy 提供支持,在创建 Collections 时,将VARCHAR
字段添加到 Collections Schema 时对其进行配置。分析器生成的标记可用于建立文本匹配索引,或转换为稀疏嵌入以进行全文检索。更多信息,请参阅文本匹配或全文搜索。
使用分析器可能会影响性能。
全文搜索:对于全文搜索,数据节点和查询节点通道消耗数据的速度更慢,因为它们必须等待标记化完成。因此,新输入的数据需要更长时间才能用于搜索。
文本匹配:对于文本匹配,索引创建速度也较慢,因为标记化需要在建立索引之前完成。
分析器剖析
Milvus 的分析器由一个标记化器和零个或多个过滤器组成。
标记化器:标记器将输入文本分解为称为标记的离散单元。根据标记符类型的不同,这些标记符可以是单词或短语。
过滤器:可以对标记符进行过滤,进一步细化标记符,例如,将标记符变成小写或删除常用词。
下面的工作流程显示了分析器是如何处理文本的。
分析器类型
Milvus 提供两种类型的分析器,以满足不同的文本处理需求。
内置分析器:这些是预定义的配置,只需最少的设置即可完成常见的文本处理任务。内置分析器不需要复杂的配置,是通用搜索的理想选择。
自定义分析器:对于更高级的需求,自定义分析器允许你通过指定标记器和零个或多个过滤器来定义自己的配置。这种自定义级别对于需要精确控制文本处理的特殊用例尤其有用。
如果在创建 Collections 时省略了分析器配置,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"
}'
过滤器
过滤器是可选组件,用于处理标记化器生成的标记,并根据需要对其进行转换或细化。例如,在对标记化术语["Vector", "Database", "Built", "for", "Scale"]
应用lowercase
过滤器后,结果可能是。
["vector", "database", "built", "for", "scale"]
自定义分析器中的过滤器可以是内置的,也可以是自定义的,具体取决于配置需求。
内置过滤器:由 Milvus 预先配置,只需最少的设置。您只需指定过滤器的名称,就能立即使用这些过滤器。以下是可直接使用的内置过滤器。
lowercase
:将文本转换为小写,确保不区分大小写进行匹配。有关详情,请参阅小写。asciifolding
:将非 ASCII 字符转换为 ASCII 对应字符,简化多语言文本处理。有关详情,请参阅ASCII 折叠。alphanumonly
:只保留字母数字字符,删除其他字符。有关详情,请参阅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"] } ] }'
使用示例
在本示例中,我们定义了一个 Collections 模式,其中包含一个用于嵌入的向量字段和两个用于文本处理功能的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
}"