文字匹配
Milvus 中的文字匹配可根據特定術語進行精確的文件檢索。此功能主要用於滿足特定條件的篩選搜尋,並可結合標量篩選來精細查詢結果,允許在符合標量條件的向量內進行相似性搜尋。
文字匹配著重於尋找查詢字詞的精確出現,而不會對匹配文件的相關性進行評分。如果您想要根據查詢字詞的語意和重要性擷取最相關的文件,我們建議您使用全文檢索。
概述
Milvus 整合了Tantivy來提供底層的倒排索引和基於詞彙的文字搜尋。對於每一個文本條目,Milvus 都會按照以下程序建立索引:
分析器:分析器會將輸入的文字標記化為單獨的字詞或標記,然後根據需要套用篩選器。這可讓 Milvus 根據這些標記建立索引。
建立索引:在文字分析之後,Milvus 會建立反向索引,將每個獨特的標記映射到包含該標記的文件。
當使用者執行文字比對時,倒置索引會被用來快速擷取所有包含該詞彙的文件。這比逐一掃描每份文件要快得多。
關鍵字匹配
啟用文字匹配
文字匹配作用於 VARCHAR欄位類型,基本上是 Milvus 中的字串資料類型。若要啟用文字匹配,請將enable_analyzer 和enable_match 都設定為True ,然後在定義收集模式時,選擇性地設定文字分析的分析器。
設定enable_analyzer 和enable_match
要啟用特定VARCHAR 欄位的文字匹配,在定義欄位模式時,請將enable_analyzer 和enable_match 參數都設定為True 。這會指示 Milvus 對文字進行標記化,並為指定欄位建立反向索引,以進行快速且有效率的文字匹配。
from pymilvus import MilvusClient, DataType
schema = MilvusClient.create_schema(enable_dynamic_field=False)
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, # Whether to enable text analysis for this field
enable_match=True # Whether to enable text match
)
schema.add_field(
field_name="embeddings",
datatype=DataType.FLOAT_VECTOR,
dim=5
)
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("id")
.dataType(DataType.Int64)
.isPrimaryKey(true)
.autoID(true)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("text")
.dataType(DataType.VarChar)
.maxLength(1000)
.enableAnalyzer(true)
.enableMatch(true)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("embeddings")
.dataType(DataType.FloatVector)
.dimension(5)
.build());
import "github.com/milvus-io/milvus/client/v2/entity"
schema := entity.NewSchema().WithDynamicFieldEnabled(false)
schema.WithField(entity.NewField().
WithName("id").
WithDataType(entity.FieldTypeInt64).
WithIsPrimaryKey(true).
WithIsAutoID(true),
).WithField(entity.NewField().
WithName("text").
WithDataType(entity.FieldTypeVarChar).
WithEnableAnalyzer(true).
WithEnableMatch(true).
WithMaxLength(1000),
).WithField(entity.NewField().
WithName("embeddings").
WithDataType(entity.FieldTypeFloatVector).
WithDim(5),
)
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: "embeddings",
data_type: DataType.FloatVector,
dim: 5,
},
];
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": "embeddings",
"dataType": "FloatVector",
"elementTypeParams": {
"dim": "5"
}
}
]
}'
可選:設定分析器
關鍵字比對的效能與準確度取決於所選擇的分析器。不同的分析器是針對各種語言和文字結構量身打造的,因此選擇正確的分析器可以顯著影響您特定使用個案的搜尋結果。
預設情況下,Milvus 使用standard 分析器,它會根據空白和標點符號來標記文字,移除長於 40 個字元的標記,並將文字轉換為小寫。應用此預設設定不需要額外參數。如需詳細資訊,請參閱標準。
在需要不同分析器的情況下,您可以使用analyzer_params 參數設定一個分析器。例如,應用english 分析器來處理英文文字:
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());
analyzerParams := map[string]any{"type": "english"}
schema.WithField(entity.NewField().
WithName("text").
WithDataType(entity.FieldTypeVarChar).
WithEnableAnalyzer(true).
WithEnableMatch(true).
WithAnalyzerParams(analyzerParams).
WithMaxLength(200),
)
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: "embeddings",
data_type: DataType.FloatVector,
dim: 5,
},
];
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": "embeddings",
"dataType": "FloatVector",
"elementTypeParams": {
"dim": "5"
}
}
]
}'
Milvus 也提供其他各種適合不同語言和情境的分析器。如需詳細資訊,請參閱分析器概述。
使用文字匹配
一旦您在收集模式中啟用了 VARCHAR 欄位的文字匹配,您可以使用TEXT_MATCH 表達式執行文字匹配。
TEXT_MATCH 表達式語法
TEXT_MATCH 表達式用來指定欄位和要搜尋的詞彙。其語法如下:
TEXT_MATCH(field_name, text)
field_name:要搜尋的 VARCHAR 欄位名稱。text:要搜尋的詞彙。根據語言和設定的分析器,多個詞彙可以用空格或其他適當的分隔符分隔。
預設情況下,TEXT_MATCH 使用OR匹配邏輯,這表示它會返回包含任何指定詞彙的文件。例如,若要搜尋text 欄位中包含machine 或deep 這個詞彙的文件,請使用下列表達式:
filter = "TEXT_MATCH(text, 'machine deep')"
String filter = "TEXT_MATCH(text, 'machine deep')";
filter := "TEXT_MATCH(text, 'machine deep')"
const filter = "TEXT_MATCH(text, 'machine deep')";
export filter="\"TEXT_MATCH(text, 'machine deep')\""
您也可以使用邏輯運算符結合多個TEXT_MATCH 表達式來執行AND匹配。
若要搜尋
text欄位中同時包含machine和deep的文件,請使用下列表達式:filter = "TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'deep')"String filter = "TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'deep')";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')\""若要搜尋
text欄位中同時包含machine和learning但不包含deep的文件,請使用下列表達式:filter = "not TEXT_MATCH(text, 'deep') and TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'learning')"String filter = "not TEXT_MATCH(text, 'deep') and TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'learning')";filter := "not TEXT_MATCH(text, 'deep') and TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'learning')"const filter = "not TEXT_MATCH(text, 'deep') and TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'learning')";export filter="\"not TEXT_MATCH(text, 'deep') and TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'learning')\""
使用文字匹配進行搜尋
文字匹配可與向量相似性搜尋結合使用,以縮窄搜尋範圍並提昇搜尋效能。在向量相似性搜尋之前使用文字匹配過濾集合,可以減少需要搜尋的文件數量,從而加快查詢時間。
在這個範例中,filter 表達式會過濾搜尋結果,使其只包含符合指定詞彙keyword1 或keyword2 的文件。然後,向量類似性搜尋會在這個經過過濾的文件子集中執行。
您可以透過設定文字高亮器來高亮搜尋結果中符合的詞彙。詳情請參閱文字高亮程式。
# 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 = client.search(
collection_name="my_collection", # 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("my_collection")
.annsField("embeddings")
.data(Collections.singletonList(queryVector)))
.filter(filter)
.topK(10)
.outputFields(Arrays.asList("id", "text"))
.build());
filter := "TEXT_MATCH(text, 'keyword1 keyword2')"
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
"my_collection", // collectionName
10, // limit
[]entity.Vector{entity.FloatVector(queryVector)},
).WithANNSField("embeddings").
WithFilter(filter).
WithOutputFields("id", "text"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
// 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: "my_collection", // 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" \
--header "Request-Timeout: 10" \
-d '{
"collectionName": "my_collection",
"annsField": "embeddings",
"data": [[0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104]],
"filter": '"$filter"',
"searchParams": {
"params": {
"nprobe": 10
}
},
"limit": 10,
"outputFields": ["text","id"]
}'
使用文字匹配進行查詢
文字匹配也可以用於查詢操作中的標量篩選。只要在query() 方法的expr 參數中指定TEXT_MATCH 表達式,就可以擷取符合給定詞彙的文件。
下面的範例擷取text 欄位包含keyword1 和keyword2 兩個詞彙的文件。
# Match entities with both `keyword1` and `keyword2`
filter = "TEXT_MATCH(text, 'keyword1') and TEXT_MATCH(text, 'keyword2')"
result = client.query(
collection_name="my_collection",
filter=filter,
output_fields=["id", "text"]
)
String filter = "TEXT_MATCH(text, 'keyword1') and TEXT_MATCH(text, 'keyword2')";
QueryResp queryResp = client.query(QueryReq.builder()
.collectionName("my_collection")
.filter(filter)
.outputFields(Arrays.asList("id", "text"))
.build()
);
filter = "TEXT_MATCH(text, 'keyword1') and TEXT_MATCH(text, 'keyword2')"
resultSet, err := client.Query(ctx, milvusclient.NewQueryOption("my_collection").
WithFilter(filter).
WithOutputFields("id", "text"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
// 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: "my_collection",
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" \
--header "Request-Timeout: 10" \
-d '{
"collectionName": "my_collection",
"filter": '"$filter"',
"outputFields": ["id", "text"]
}'
注意事項
為欄位啟用詞彙匹配會觸發建立反向索引,這會消耗儲存資源。在決定啟用此功能時,請考慮對儲存的影響,因為它會因文字大小、獨特標記和使用的分析器而異。
一旦您在模式中定義了分析器,其設定就會永久適用於該集合。如果您認為不同的分析器更符合您的需求,您可以考慮刪除現有的集合,並使用所需的分析器設定建立新的集合。
filter表達式中的 Escape 規則:在表達式中以雙引號或單引號括住的字元會被解釋為字串常數。如果字串常數包含轉換字元,則必須使用轉換順序來表示轉換字元。例如,使用
\\表示\,使用\\t表示制表符\t,使用\\n表示換行符。如果字串常數由單引號括住,常數內的單引號應表示為
\\',而雙引號可表示為"或\\"。 例如:'It\\'s milvus'。如果字串常數由雙引號括住,常數中的雙引號應表示為
\\",而單引號可表示為'或\\'。 例:"He said \\"Hi\\""。