跳到主要内容

全文搜索

全文搜索是一种在文本数据集中检索包含特定术语或短语的文档,然后根据相关性对结果进行排名的功能。此功能克服了语义搜索的限制,后者可能会忽略精确术语,确保您收到最准确且与上下文相关的结果。此外,它通过接受原始文本输入简化了向量搜索,自动将您的文本数据转换为稀疏嵌入,而无需手动生成向量嵌入。

使用 BM25 算法进行相关性评分,此功能在检索增强生成(RAG)场景中特别有价值,它优先考虑与特定搜索术语密切匹配的文档。

通过将全文搜索与基于语义的密集向量搜索相结合,您可以增强搜索结果的准确性和相关性。有关更多信息,请参阅 混合搜索

概述

全文搜索通过消除手动嵌入的需要简化了基于文本的搜索过程。此功能通过以下工作流程运行:

  1. 文本输入:您插入原始文本文档或提供查询文本,无需任何手动嵌入。

  2. 文本分析:Milvus 使用分析器将输入文本标记化为单独的、可搜索的术语。

  3. 函数处理:内置函数接收标记化的术语并将其转换为稀疏向量表示。

  4. Collection 存储:Milvus 将这些稀疏嵌入存储在 collection 中以进行高效检索。

  5. BM25 评分:在搜索期间,Milvus 应用 BM25 算法为存储的文档计算分数,并根据与查询文本的相关性对匹配结果进行排名。

Full Text Search

要使用全文搜索,请遵循以下主要步骤:

  1. 创建 collection:设置具有必要 field 的 collection 并定义函数以将原始文本转换为稀疏嵌入。

  2. 插入数据:将原始文本文档摄取到 collection 中。

  3. 执行搜索:使用查询文本搜索您的 collection 并检索相关结果。

为全文搜索创建 collection

要启用全文搜索,请使用特定 schema 创建 collection。此 schema 必须包含三个必要的 field:

  • 在 collection 中唯一标识每个 entity 的主 field。

  • 存储原始文本文档的 VARCHAR field,其 enable_analyzer 属性设置为 True。这允许 Milvus 将文本标记化为特定术语以进行函数处理。

  • 保留用于存储 Milvus 将为 VARCHAR field 自动生成的稀疏嵌入的 SPARSE_FLOAT_VECTOR field。

在此配置中,

  • id:作为 primary key,并通过 auto_id=True 自动生成。

  • text:存储用于全文搜索操作的原始文本数据。数据类型必须是 VARCHAR,因为 VARCHAR 是 Milvus 用于文本存储的字符串数据类型。设置 enable_analyzer=True 允许 Milvus 对文本进行分词。默认情况下,Milvus 使用 standard 分析器进行文本分析。要配置不同的分析器,请参阅分析器概述

  • sparse:保留用于存储内部生成的稀疏嵌入以进行全文搜索操作的向量 field。数据类型必须是 SPARSE_FLOAT_VECTOR

现在,定义一个将文本转换为稀疏向量表示的函数,然后将其添加到 schema 中:

bm25_function = Function(
name="text_bm25_emb", # Function name
input_field_names=["text"], # Name of the VARCHAR field containing raw text data
output_field_names=["sparse"], # Name of the SPARSE_FLOAT_VECTOR field reserved to store generated embeddings
function_type=FunctionType.BM25, # Set to `BM25`
)

schema.add_function(bm25_function)
import io.milvus.common.clientenum.FunctionType;
import io.milvus.v2.service.collection.request.CreateCollectionReq.Function;

import java.util.*;

schema.addFunction(Function.builder()
.functionType(FunctionType.BM25)
.name("text_bm25_emb")
.inputFieldNames(Collections.singletonList("text"))
.outputFieldNames(Collections.singletonList("sparse"))
.build());
function := entity.NewFunction().
WithName("text_bm25_emb").
WithInputFields("text").
WithOutputFields("sparse").
WithType(entity.FunctionTypeBM25)
schema.WithFunction(function)
const functions = [
{
name: 'text_bm25_emb',
description: 'bm25 function',
type: FunctionType.BM25,
input_field_names: ['text'],
output_field_names: ['sparse'],
params: {},
},
]
export schema='{
"autoId": true,
"enabledDynamicField": false,
"fields": [
{
"fieldName": "id",
"dataType": "Int64",
"isPrimary": true
},
{
"fieldName": "text",
"dataType": "VarChar",
"elementTypeParams": {
"max_length": 1000,
"enable_analyzer": true
}
},
{
"fieldName": "sparse",
"dataType": "SparseFloatVector"
}
],
"functions": [
{
"name": "text_bm25_emb",
"type": "BM25",
"inputFieldNames": ["text"],
"outputFieldNames": ["sparse"],
"params": {}
}
]
}'

参数

描述

name

函数的名称。此函数将 text field 中的原始文本转换为可搜索的向量,这些向量将存储在 sparse field 中。

input_field_names

需要进行文本到稀疏向量转换的 VARCHAR field 的名称。对于 FunctionType.BM25,此参数只接受一个 field 名称。

output_field_names

存储内部生成的稀疏向量的 field 名称。对于 FunctionType.BM25,此参数只接受一个 field 名称。

function_type

要使用的函数类型。将值设置为 FunctionType.BM25

对于具有多个需要文本到稀疏向量转换的 VARCHAR field 的 collection,请向 collection schema 添加单独的函数,确保每个函数具有唯一的名称和 output_field_names 值。

配置 index

定义具有必要 field 和内置函数的 schema 后,为您的 collection 设置 index。为了简化此过程,使用 AUTOINDEX 作为 index_type,这是一个允许 Milvus 根据数据结构选择和配置最合适的 index 类型的选项。

index_params = MilvusClient.prepare_index_params()

index_params.add_index(
field_name="sparse",

index_type="SPARSE_INVERTED_INDEX",
metric_type="BM25",
params={
"inverted_index_algo": "DAAT_MAXSCORE",
"bm25_k1": 1.2,
"bm25_b": 0.75
}

)
import io.milvus.v2.common.IndexParam;

List<IndexParam> indexes = new ArrayList<>();
indexes.add(IndexParam.builder()
.fieldName("sparse")
.indexType(IndexParam.IndexType.AUTOINDEX)
.metricType(IndexParam.MetricType.BM25)
.build());
indexOption := milvusclient.NewCreateIndexOption("my_collection", "sparse",
index.NewAutoIndex(entity.MetricType(entity.BM25)))
const index_params = [
{
field_name: "sparse",
metric_type: "BM25",
index_type: "AUTOINDEX",
},
];
export indexParams='[
{
"fieldName": "sparse",
"metricType": "BM25",
"indexType": "AUTOINDEX"
}
]'

参数

描述

field_name

要索引的向量 field 的名称。对于全文搜索,这应该是存储生成的稀疏向量的 field。在此示例中,将值设置为 sparse

index_type

要创建的索引类型。AUTOINDEX 允许 Milvus 自动优化索引设置。如果您需要对索引设置有更多控制,您可以从 Milvus 中为稀疏向量可用的各种索引类型中选择。有关更多信息,请参阅 Milvus 支持的索引

metric_type

对于全文搜索功能,此参数的值必须专门设置为 BM25

params

特定于索引的其他参数字典。

params.inverted_index_algo

用于构建和查询索引的算法。有效值:

  • "DAAT_MAXSCORE"(默认):使用 MaxScore 算法的优化文档逐一(DAAT)查询处理。MaxScore 通过跳过可能影响很小的术语和文档,为高 k 值或具有多个术语的查询提供更好的性能。它通过基于最大影响分数将术语分为必要和非必要组来实现这一点,专注于能够对 top-k 结果做出贡献的术语。

  • "DAAT_WAND":使用 WAND 算法的优化 DAAT 查询处理。WAND 通过利用最大影响分数跳过非竞争性文档来评估较少的命中文档,但它具有更高的每次命中开销。这使 WAND 对于具有小 k 值或短查询的查询更有效,在这些情况下跳过更可行。

  • "TAAT_NAIVE":基本术语逐一(TAAT)查询处理。与 DAAT_MAXSCOREDAAT_WAND 相比,它速度较慢,TAAT_NAIVE 提供了独特的优势。与使用缓存最大影响分数的 DAAT 算法不同,这些分数无论全局 collection 参数(avgdl)如何变化都保持静态,TAAT_NAIVE 动态适应这些变化。

params.bm25_k1

控制术语频率饱和度。较高的值增加术语频率在文档排名中的重要性。值范围:[1.2, 2.0]。

params.bm25_b

控制文档长度归一化的程度。通常使用 0 到 1 之间的值,常见默认值约为 0.75。值为 1 表示没有长度归一化,值为 0 表示完全归一化。

Create the collection

Now create the collection using the schema and index parameters defined.

创建 collection

现在使用定义的 schema 和索引参数创建 collection。

client.create_collection(
collection_name='my_collection',
schema=schema,
index_params=index_params
)
import io.milvus.v2.service.collection.request.CreateCollectionReq;

CreateCollectionReq requestCreate = CreateCollectionReq.builder()
.collectionName("my_collection")
.collectionSchema(schema)
.indexParams(indexes)
.build();
client.createCollection(requestCreate);
err = client.CreateCollection(ctx,
milvusclient.NewCreateCollectionOption("my_collection", schema).
WithIndexOptions(indexOption))
if err != nil {
fmt.Println(err.Error())
// handle error
}
await client.create_collection(
collection_name: 'my_collection',
schema: schema,
index_params: index_params,
functions: functions
);
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\": \"my_collection\",
\"schema\": $schema,
\"indexParams\": $indexParams
}"

插入文本数据

设置好 collection 和索引后,您就可以插入文本数据了。在此过程中,您只需要提供原始文本。我们之前定义的内置函数会自动为每个文本条目生成相应的稀疏向量。

client.insert('my_collection', [
{'text': 'information retrieval is a field of study.'},
{'text': 'information retrieval focuses on finding relevant information in large datasets.'},
{'text': 'data mining and information retrieval overlap in research.'},
])
import com.google.gson.Gson;
import com.google.gson.JsonObject;

import io.milvus.v2.service.vector.request.InsertReq;

Gson gson = new Gson();
List<JsonObject> rows = Arrays.asList(
gson.fromJson("{\"text\": \"information retrieval is a field of study.\"}", JsonObject.class),
gson.fromJson("{\"text\": \"information retrieval focuses on finding relevant information in large datasets.\"}", JsonObject.class),
gson.fromJson("{\"text\": \"data mining and information retrieval overlap in research.\"}", JsonObject.class)
);

client.insert(InsertReq.builder()
.collectionName("my_collection")
.data(rows)
.build());
// go
await client.insert({
collection_name: 'my_collection',
data: [
{'text': 'information retrieval is a field of study.'},
{'text': 'information retrieval focuses on finding relevant information in large datasets.'},
{'text': 'data mining and information retrieval overlap in research.'},
]);
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"data": [
{"text": "information retrieval is a field of study."},
{"text": "information retrieval focuses on finding relevant information in large datasets."},
{"text": "data mining and information retrieval overlap in research."}
],
"collectionName": "my_collection"
}'

执行全文搜索

在您的 collection 中插入数据后,您可以使用原始文本查询执行全文搜索。Milvus 自动将您的查询转换为稀疏向量,使用 BM25 算法对匹配的搜索结果进行排名,然后返回 topK(limit)结果。

search_params = {
'params': {'drop_ratio_search': 0.2},
}

client.search(
collection_name='my_collection',
data=['whats the focus of information retrieval?'],
anns_field='sparse',
limit=3,
search_params=search_params
)
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.EmbeddedText;
import io.milvus.v2.service.vector.response.SearchResp;

Map<String,Object> searchParams = new HashMap<>();
searchParams.put("drop_ratio_search", 0.2);
SearchResp searchResp = client.search(SearchReq.builder()
.collectionName("my_collection")
.data(Collections.singletonList(new EmbeddedText("whats the focus of information retrieval?")))
.annsField("sparse")
.topK(3)
.searchParams(searchParams)
.outputFields(Collections.singletonList("text"))
.build());
annSearchParams := index.NewCustomAnnParam()
annSearchParams.WithExtraParam("drop_ratio_search", 0.2)
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
"my_collection", // collectionName
3, // limit
[]entity.Vector{entity.Text("whats the focus of information retrieval?")},
).WithConsistencyLevel(entity.ClStrong).
WithANNSField("sparse").
WithAnnParam(annSearchParams).
WithOutputFields("text"))
if err != nil {
fmt.Println(err.Error())
// handle error
}

for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs.FieldData().GetScalars())
fmt.Println("Scores: ", resultSet.Scores)
fmt.Println("text: ", resultSet.GetColumn("text").FieldData().GetScalars())
}
await client.search(
collection_name: 'my_collection',
data: ['whats the focus of information retrieval?'],
anns_field: 'sparse',
limit: 3,
params: {'drop_ratio_search': 0.2},
)
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--data-raw '{
"collectionName": "my_collection",
"data": [
"whats the focus of information retrieval?"
],
"annsField": "sparse",
"limit": 3,
"outputFields": [
"text"
],
"searchParams":{
"params":{
"drop_ratio_search":0.2
}
}
}'

参数

描述

search_params

包含搜索参数的字典。

params.drop_ratio_search

在搜索期间忽略的低重要性术语的比例。有关详细信息,请参阅 稀疏向量

data

原始查询文本。

anns_field

包含内部生成的稀疏向量的 field 名称。

limit

要返回的最大匹配数。