Pencarian Teks Lengkap
Pencarian teks lengkap adalah fitur yang mengambil dokumen yang mengandung istilah atau frasa tertentu dalam kumpulan data teks, kemudian mengurutkan hasilnya berdasarkan relevansi. Fitur ini mengatasi keterbatasan pencarian semantik, yang mungkin mengabaikan istilah yang tepat, sehingga memastikan Anda mendapatkan hasil yang paling akurat dan relevan secara kontekstual. Selain itu, fitur ini menyederhanakan pencarian vektor dengan menerima masukan teks mentah, secara otomatis mengubah data teks Anda menjadi embedding spars tanpa perlu membuat embedding vektor secara manual.
Dengan menggunakan algoritma BM25 untuk penilaian relevansi, fitur ini sangat berguna dalam skenario Retrieval-Augmented Generation (RAG), di mana fitur ini memprioritaskan dokumen yang sangat sesuai dengan istilah pencarian tertentu.
Dengan mengintegrasikan pencarian teks lengkap dengan pencarian vektor padat berbasis semantik, Anda dapat meningkatkan akurasi dan relevansi hasil pencarian. Untuk informasi lebih lanjut, lihat Pencarian Hibrida.
Implementasi BM25
Milvus menyediakan pencarian teks lengkap yang didukung oleh algoritma relevansi BM25, sebuah fungsi penilaian yang banyak digunakan dalam sistem pencarian informasi, dan Milvus mengintegrasikannya ke dalam alur kerja pencarian untuk memberikan hasil teks yang akurat dan diurutkan berdasarkan relevansi.
Pencarian teks lengkap di Milvus mengikuti alur kerja berikut:
Masukan teks mentah: Anda memasukkan dokumen teks atau memberikan kueri menggunakan teks biasa, tanpa memerlukan model embedding.
Analisis teks: Milvus menggunakan penganalisis untuk memproses teks Anda menjadi istilah-istilah bermakna yang dapat diindeks dan dicari.
Pemrosesan fungsi BM25: Fungsi bawaan mengubah istilah-istilah ini menjadi representasi vektor spars yang dioptimalkan untuk penilaian BM25.
Penyimpanan koleksi: Milvus menyimpan embedding langka yang dihasilkan dalam sebuah koleksi untuk pengambilan dan pemeringkatan yang cepat.
Penilaian relevansi BM25: Saat pencarian, Milvus menerapkan fungsi penilaian BM25 untuk menghitung relevansi dokumen dan menampilkan hasil yang diurutkan berdasarkan kesesuaian terbaik dengan istilah kueri.
Pencarian Teks Lengkap
Untuk menggunakan pencarian teks lengkap, ikuti langkah-langkah utama berikut:
Buat koleksi: Atur bidang yang diperlukan dan tentukan fungsi BM25 yang mengubah teks mentah menjadi representasi vektor langka.
Masukkan data: Impor dokumen teks mentah Anda ke dalam koleksi.
Lakukan pencarian: Gunakan teks kueri dalam bahasa alami untuk mengambil hasil yang diurutkan berdasarkan relevansi BM25.
Buat koleksi untuk pencarian teks lengkap BM25
Untuk mengaktifkan pencarian teks lengkap yang didukung BM25, Anda harus menyiapkan koleksi dengan bidang yang diperlukan, tentukan fungsi BM25 untuk menghasilkan vektor spars, konfigurasikan indeks, lalu buat koleksi tersebut.
Tentukan bidang skema
Skema koleksi Anda harus mencakup setidaknya tiga bidang yang diperlukan:
Bidang utama: Mengidentifikasi setiap entitas dalam koleksi secara unik.
Bidang string (
VARCHARatauTEXT): Menyimpan dokumen teks mentah. Harus mengaturenable_analyzer=Trueagar Milvus dapat memproses teks untuk peringkat relevansi BM25. Secara default, Milvus menggunakanstandardanalyzer untuk analisis teks. Untuk mengonfigurasi analyzer yang berbeda, lihat Ikhtisar Analyzer. Contoh-contoh pada halaman ini menggunakanVARCHAR; untuk teks panjang, Anda dapat mendefinisikan bidang input sebagaiTEXTdan mengabaikanmax_length. Untuk contoh lengkap, lihat Bidang Teks.Bidang vektor jarang (
SPARSE_FLOAT_VECTOR): Menyimpan embedding jarang yang dihasilkan secara otomatis oleh fungsi BM25.
from pymilvus import MilvusClient, DataType, Function, FunctionType
client = MilvusClient(
uri="http://localhost:19530",
token="root:Milvus"
)
schema = client.create_schema()
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True, auto_id=True) # Primary field
schema.add_field(field_name="text", datatype=DataType.VARCHAR, max_length=1000, enable_analyzer=True) # Text field
schema.add_field(field_name="sparse", datatype=DataType.SPARSE_FLOAT_VECTOR) # Sparse vector field; no dim required for sparse vectors
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()
.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)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("sparse")
.dataType(DataType.SparseFloatVector)
.build());
import (
"context"
"fmt"
"github.com/milvus-io/milvus/client/v2/column"
"github.com/milvus-io/milvus/client/v2/entity"
"github.com/milvus-io/milvus/client/v2/index"
"github.com/milvus-io/milvus/client/v2/milvusclient"
)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
milvusAddr := "localhost:19530"
client, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
Address: milvusAddr,
})
if err != nil {
fmt.Println(err.Error())
// handle error
}
defer client.Close(ctx)
schema := entity.NewSchema()
schema.WithField(entity.NewField().
WithName("id").
WithDataType(entity.FieldTypeInt64).
WithIsPrimaryKey(true).
WithIsAutoID(true),
).WithField(entity.NewField().
WithName("text").
WithDataType(entity.FieldTypeVarChar).
WithEnableAnalyzer(true).
WithMaxLength(1000),
).WithField(entity.NewField().
WithName("sparse").
WithDataType(entity.FieldTypeSparseVector),
)
import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";
const address = "http://localhost:19530";
const token = "root:Milvus";
const client = new MilvusClient({address, token});
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: "sparse",
data_type: DataType.SparseFloatVector,
},
];
console.log(res.results)
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"
}
]
}'
Dalam konfigurasi di atas,
id: berfungsi sebagai kunci utama dan dihasilkan secara otomatis denganauto_id=True.text: menyimpan data teks mentah Anda untuk operasi pencarian teks lengkap. Bidang ini dapat menggunakan `VARCHAR` untuk teks terbatas atau `TEXT` untuk konten sumber yang panjang.sparse: bidang vektor yang disediakan untuk menyimpan embedding jarang yang dihasilkan secara internal guna operasi pencarian teks lengkap. Tipe datanya harusSPARSE_FLOAT_VECTOR.
Tentukan fungsi BM25
Fungsi BM25 mengubah teks yang telah ditokenisasi menjadi vektor langka yang mendukung penilaian BM25.
Tentukan fungsi tersebut dan tambahkan ke skema Anda:
bm25_function = Function(
name="text_bm25_emb", # Function name
input_field_names=["text"], # Name of the VARCHAR or TEXT 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": {}
}
]
}'
Parameter |
Deskripsi |
|---|---|
|
Nama fungsi. Fungsi ini mengubah teks mentah Anda dari bidang ` |
|
Nama bidang ` |
|
Nama bidang tempat vektor langka yang dihasilkan secara internal akan disimpan. Untuk ` |
|
Jenis fungsi yang akan digunakan. Harus berupa ` |
Jika beberapa bidang teks memerlukan pemrosesan BM25, tentukan satu fungsi BM25 per bidang, masing-masing dengan nama dan bidang keluaran yang unik.
Konfigurasikan indeks
Setelah mendefinisikan skema dengan bidang-bidang yang diperlukan dan fungsi bawaan, atur indeks untuk koleksi Anda.
index_params = client.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;
Map<String,Object> params = new HashMap<>();
params.put("inverted_index_algo", "DAAT_MAXSCORE");
params.put("bm25_k1", 1.2);
params.put("bm25_b", 0.75);
List<IndexParam> indexes = new ArrayList<>();
indexes.add(IndexParam.builder()
.fieldName("sparse")
.indexType(IndexParam.IndexType.AUTOINDEX)
.metricType(IndexParam.MetricType.BM25)
.extraParams(params)
.build());
indexOption := milvusclient.NewCreateIndexOption("my_collection", "sparse",
index.NewAutoIndex(entity.MetricType(entity.BM25)))
.WithExtraParam("inverted_index_algo", "DAAT_MAXSCORE")
.WithExtraParam("bm25_k1", 1.2)
.WithExtraParam("bm25_b", 0.75)
const index_params = [
{
field_name: "sparse",
metric_type: "BM25",
index_type: "SPARSE_INVERTED_INDEX",
params: {
"inverted_index_algo": "DAAT_MAXSCORE",
"bm25_k1": 1.2,
"bm25_b": 0.75
}
},
];
export indexParams='[
{
"fieldName": "sparse",
"metricType": "BM25",
"indexType": "AUTOINDEX",
"params":{
"inverted_index_algo": "DAAT_MAXSCORE",
"bm25_k1": 1.2,
"bm25_b": 0.75
}
}
]'
Parameter |
Deskripsi |
|---|---|
|
Nama bidang vektor yang akan diindeks. Untuk pencarian teks lengkap, bidang ini haruslah bidang yang menyimpan vektor sparse yang dihasilkan. Dalam contoh ini, atur nilainya menjadi |
|
Jenis indeks yang akan dibuat. Untuk pencarian teks lengkap BM25 di Milvus, atur nilai ini menjadi |
|
Nilai untuk parameter ini harus diatur ke |
|
Kamus parameter tambahan yang spesifik untuk indeks. |
|
Algoritma yang digunakan untuk membangun dan melakukan kueri pada indeks terbalik BM25 yang jarang. Nilai yang valid:
|
|
Mengontrol saturasi frekuensi istilah. Nilai yang lebih tinggi meningkatkan bobot frekuensi istilah dalam peringkat dokumen. Rentang yang disarankan: [1,2; 2,0]. Nilai default: 1,2. |
|
Mengontrol sejauh mana panjang dokumen dinormalisasi. Nilai antara 0 dan 1 biasanya digunakan, dengan nilai default 0,75. Nilai 0 berarti tidak ada normalisasi panjang, sedangkan nilai 1 berarti normalisasi panjang penuh. |
Buat koleksi
Sekarang buat koleksi menggunakan skema dan parameter indeks yang telah ditentukan.
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" \
--header "Request-Timeout: 10" \
-d "{
\"collectionName\": \"my_collection\",
\"schema\": $schema,
\"indexParams\": $indexParams
}"
Masukkan data teks
Setelah menyiapkan koleksi dan indeks, Anda siap untuk menyisipkan data teks. Dalam proses ini, Anda hanya perlu menyediakan teks mentah. Fungsi bawaan yang telah kita tentukan sebelumnya secara otomatis menghasilkan vektor spars yang sesuai untuk setiap entri teks.
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" \
--header "Request-Timeout: 10" \
-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"
}'
Lakukan pencarian teks lengkap
Setelah Anda menyisipkan data ke dalam koleksi, Anda dapat melakukan pencarian teks lengkap menggunakan kueri teks mentah. Milvus secara otomatis mengubah kueri Anda menjadi vektor spars dan menentukan peringkat hasil pencarian yang cocok menggunakan algoritma BM25, lalu mengembalikan hasil topK (limit).
Anda dapat menyorot istilah yang cocok dalam hasil pencarian dengan mengonfigurasi penyorot teks. Lihat Penyorot Teks untuk detailnya.
res = client.search(
collection_name='my_collection',
data=['whats the focus of information retrieval?'],
anns_field='sparse',
output_fields=['text'], # Fields to return in search results; sparse field cannot be output
limit=3,
)
print(res)
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<>();
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()
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',
output_fields: ['text'],
limit: 3,
)
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--header "Request-Timeout: 10" \
--data-raw '{
"collectionName": "my_collection",
"data": [
"whats the focus of information retrieval?"
],
"annsField": "sparse",
"limit": 3,
"outputFields": [
"text"
],
"searchParams":{
"params":{}
}
}'
Parameter |
Deskripsi |
|---|---|
|
Sebuah kamus yang berisi parameter pencarian. |
|
Proporsi istilah dengan tingkat kepentingan rendah yang akan diabaikan selama pencarian. Nilai harus berada dalam rentang [0,0; 1,0). Untuk detailnya, lihat Vektor Jarang. |
|
Teks kueri mentah dalam bahasa alami. Milvus secara otomatis mengubah kueri teks Anda menjadi vektor spars menggunakan fungsi BM25 — jangan berikan vektor yang telah dihitung sebelumnya. |
|
Nama bidang yang berisi vektor spars yang dihasilkan secara internal. |
|
Daftar nama bidang yang akan ditampilkan dalam hasil pencarian. Mendukung semua bidang kecuali bidang vektor langka yang berisi embedding yang dihasilkan oleh BM25. Bidang keluaran umum meliputi bidang kunci utama (misalnya, |
|
Jumlah maksimum hasil pencocokan teratas yang akan ditampilkan. |
FAQ
Apakah saya dapat menampilkan atau mengakses vektor spars yang dihasilkan oleh fungsi BM25 dalam pencarian teks lengkap?
Tidak, vektor spars yang dihasilkan oleh fungsi BM25 tidak dapat diakses atau ditampilkan secara langsung dalam pencarian teks lengkap. Berikut rinciannya:
Fungsi BM25 menghasilkan vektor spars secara internal untuk pemeringkatan dan pengambilan hasil
Vektor-vektor ini disimpan dalam bidang sparse tetapi tidak dapat dimasukkan ke dalam
output_fieldsAnda hanya dapat menampilkan bidang teks asli dan metadata (seperti
id,text)
Contoh:
# ❌ This throws an error - you cannot output the sparse field
client.search(
collection_name='my_collection',
data=['query text'],
anns_field='sparse',
output_fields=['text', 'sparse'] # 'sparse' causes an error
limit=3,
search_params=search_params
)
# ✅ This works - output text fields only
client.search(
collection_name='my_collection',
data=['query text'],
anns_field='sparse',
output_fields=['text']
limit=3,
search_params=search_params
)
Mengapa saya perlu mendefinisikan bidang vektor spars jika saya tidak dapat mengaksesnya?
Bidang vektor sparsitas berfungsi sebagai indeks pencarian internal, mirip dengan indeks basis data yang tidak berinteraksi langsung dengan pengguna.
Alasan Desain:
Pemisahan Tanggung Jawab: Anda bekerja dengan teks (input/output), Milvus menangani vektor (pemrosesan internal)
Kinerja: Vektor langka yang dihitung sebelumnya memungkinkan pemeringkatan BM25 yang cepat selama kueri
Pengalaman Pengguna: Menyembunyikan operasi vektor yang kompleks di balik antarmuka teks yang sederhana
Jika Anda memerlukan akses ke vektor:
Gunakan operasi vektor spars yang dilakukan secara manual, bukan pencarian teks lengkap
Buat koleksi terpisah untuk alur kerja vektor langka khusus
Untuk detailnya, lihat Vektor Jarang.