Совпадение по фразеCompatible with Milvus 2.5.17+

Поиск по фразе позволяет находить документы, содержащие термины запроса в виде точной фразы. По умолчанию слова должны встречаться в том же порядке и непосредственно рядом друг с другом. Например, запрос «робототехника машинное обучение» найдет текст типа «…типичные модели машинного обучения в робототехнике…», где слова «робототехника», «машинное» и «обучение» идут последовательно, без других слов между ними.

Однако в реальных сценариях строгое фразное сопоставление может быть слишком жестким. Возможно, вам нужно найти текст типа «…модели машинного обучения, широко применяемые в робототехнике…». Здесь присутствуют те же ключевые слова, но они не расположены рядом и не в исходном порядке. Для решения этой проблемы фразное сопоставление поддерживает параметр « slop », который обеспечивает гибкость. Значение параметра « slop » определяет, сколько позиционных сдвигов допускается между терминами в фразе. Например, если значение параметра « slop » равно 1, запрос «machine learning» может сопоставляться с текстом типа «…machine deep learning…», где одно слово («deep») разделяет исходные термины.

Обзор

Функция поиска по фразам, реализованная с помощью библиотеки поисковой системы Tantivy, работает за счёт анализа информации о положении слов в документах. На приведённой ниже схеме показан этот процесс:

Phrase Match Workflow Рабочий процесс поиска по фразам

  1. Токенизация документа: при загрузке документов в Milvus текст разбивается на токены (отдельные слова или термины) с помощью анализатора, при этом для каждого токена фиксируется информация о его позиции. Например, doc_1 токенизируется в [«machine» (pos=0), «learning» (pos=1), «boosts» (pos=2), «efficiency» (pos=3)]. Для получения дополнительной информации об анализаторах см. раздел «Обзор анализаторов».

  2. Создание инвертированного индекса: Milvus создаёт инвертированный индекс, сопоставляя каждый токен с документом (документами), в котором он встречается, и с позициями этого токена в этих документах.

  3. Сопоставление фраз: при выполнении фразового запроса Milvus ищет каждый токен в инвертированном индексе и проверяет их позиции, чтобы определить, появляются ли они в правильном порядке и на нужном расстоянии друг от друга. Параметр « slop » контролирует максимальное количество позиций, допустимое между совпадающими токенами:

    • slop = 0 означает, что токены должны встречаться в точном порядке и непосредственно рядом друг с другом (т. е. без лишних слов между ними).

      • В примере точно соответствует только doc_1 («machine» в позиции 0, «learning» в позиции 1).
    • slop = 2 допускает до двух позиций гибкости или перестановки между совпадающими токенами.

      • Это допускает обратный порядок («learning machine») или небольшой промежуток между токенами.

      • Следовательно, совпадают doc_1, doc_2 («learning» в позиции 0, «machine» в позиции 1) и doc_3 («learning» в позиции 1, «machine» в позиции 2).

Включение фразового сопоставления

Фразовое сопоставление работает с типом поля « VARCHAR » — типом данных «string» в Milvus. Чтобы включить фразовое сопоставление, настройте схему коллекции, установив для параметров « enable_analyzer » и « enable_match » значение « True », аналогично текстовому сопоставлению.

Установите значения enable_analyzer и enable_match

Чтобы включить поиск по фразам для конкретного поля VARCHAR, при определении схемы поля установите для обоих параметров enable_analyzer и enable_match значение True. Эта настройка указывает Milvus на необходимость токенизации текста и создания инвертированного индекса с позиционной информацией, необходимой для эффективного поиска по фразам.

Ниже приведён пример определения схемы, позволяющий включить сопоставление фраз:

from pymilvus import MilvusClient, DataType

# Create a schema for a new collection
schema = MilvusClient.create_schema(enable_dynamic_field=False)
schema.add_field(
    field_name="id",
    datatype=DataType.INT64,
    is_primary=True,
    auto_id=True
)
# Add a VARCHAR field configured for phrase matching
schema.add_field(
    field_name='text',                 # Name of the field
    datatype=DataType.VARCHAR,         # Field data type set as VARCHAR (string)
    max_length=1000,                   # Maximum length of the string
    enable_analyzer=True,              # Enables text analysis (tokenization)
    enable_match=True                  # Enables inverted indexing for phrase matching
)
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;

// Create a schema for a new collection
CreateCollectionReq.CollectionSchema schema = CreateCollectionReq.CollectionSchema.builder()
        .enableDynamicField(false)
        .build();
schema.addField(AddFieldReq.builder()
        .fieldName("id")
        .dataType(DataType.Int64)
        .isPrimaryKey(true)
        .autoID(true)
        .build());
// Add a VARCHAR field configured for phrase matching
schema.addField(AddFieldReq.builder()
        .fieldName("text")              // Name of the field
        .dataType(DataType.VarChar)     // Field data type set as VARCHAR (string)
        .maxLength(1000)                // Maximum length of the string
        .enableAnalyzer(true)           // Enables text analysis (tokenization)
        .enableMatch(true)              // Enables inverted indexing for phrase matching
        .build());
schema.addField(AddFieldReq.builder()
        .fieldName("embeddings")
        .dataType(DataType.FloatVector)
        .dimension(5)
        .build());
import "github.com/milvus-io/milvus/client/v2/entity"

// Create a schema for a new collection
schema := entity.NewSchema().WithDynamicFieldEnabled(false)
schema.WithField(entity.NewField().
    WithName("id").
    WithDataType(entity.FieldTypeInt64).
    WithIsPrimaryKey(true).
    WithIsAutoID(true),
).WithField(entity.NewField().
    WithName("text").                      // Name of the field
    WithDataType(entity.FieldTypeVarChar). // Field data type set as VARCHAR (string)
    WithMaxLength(1000).                   // Maximum length of the string
    WithEnableAnalyzer(true).              // Enables text analysis (tokenization)
    WithEnableMatch(true),                 // Enables inverted indexing for phrase matching
).WithField(entity.NewField().
    WithName("embeddings").
    WithDataType(entity.FieldTypeFloatVector).
    WithDim(5),
)
import { DataType } from "@zilliz/milvus2-sdk-node";

// Create a schema for a new collection
const schema = [
  {
    name: "id",
    data_type: DataType.Int64,
    is_primary_key: true,
    autoID: true,
  },
  // Add a VARCHAR field configured for phrase matching
  {
    name: "text", // Name of the field
    data_type: DataType.VarChar, // Field data type set as VARCHAR (string)
    max_length: 1000, // Maximum length of the string
    enable_analyzer: true, // Enables text analysis (tokenization)
    enable_match: true, // Enables inverted indexing for phrase matching
  },
  {
    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"
                }
            }
        ]
    }'
#include "milvus/types/CollectionSchema.h"

// Create a schema for a new collection
milvus::CollectionSchema schema("tech_articles");
schema.SetEnableDynamicField(false);
schema.AddField(milvus::FieldSchema("id", milvus::DataType::INT64, "", true, true));
// Add a VARCHAR field configured for phrase matching
schema.AddField(milvus::FieldSchema("text", milvus::DataType::VARCHAR)  // Name of the field
                    .WithMaxLength(1000)    // Maximum length of the string
                    .EnableAnalyzer(true)   // Enables text analysis (tokenization)
                    .EnableMatch(true));    // Enables inverted indexing for phrase matching
schema.AddField(milvus::FieldSchema("embeddings", milvus::DataType::FLOAT_VECTOR)
                    .WithDimension(5));

Необязательно: настройка анализатора

Точность сопоставления фраз в значительной степени зависит от анализатора, используемого для токенизации ваших текстовых данных. Различные анализаторы подходят для разных языков и форматов текста, что влияет на токенизацию и точность позиционного сопоставления. Выбор подходящего анализатора для вашего конкретного случая использования позволит оптимизировать результаты сопоставления фраз.

По умолчанию Milvus использует стандартный анализатор, который разбивает текст на токены на основе пробелов и знаков препинания, удаляет токены длиной более 40 символов и преобразует текст в нижний регистр. Для использования по умолчанию дополнительные параметры не требуются. Подробности см. в разделе «Стандартный анализатор ».

Если вашему приложению требуется конкретный анализатор, настройте его с помощью параметра ` analyzer_params `. Например, вот как настроить анализатор ` english ` для сопоставления фраз в тексте на английском языке:

# Define analyzer parameters for English-language tokenization
analyzer_params = {
    "type": "english"
}

# Add the VARCHAR field with the English analyzer enabled
schema.add_field(
    field_name='text',                 # Name of the field
    datatype=DataType.VARCHAR,         # Field data type set as VARCHAR
    max_length=1000,                   # Maximum length of the string
    enable_analyzer=True,              # Enables text analysis
    analyzer_params=analyzer_params,   # Specifies the analyzer configuration
    enable_match=True                  # Enables inverted indexing for phrase matching
)
// Define analyzer parameters for English-language tokenization
Map<String, Object> analyzerParams = new HashMap<>();
analyzerParams.put("type", "english");

// Add the VARCHAR field with the English analyzer enabled
schema.addField(AddFieldReq.builder()
        .fieldName("text")              // Name of the field
        .dataType(DataType.VarChar)     // Field data type set as VARCHAR
        .maxLength(1000)                // Maximum length of the string
        .enableAnalyzer(true)           // Enables text analysis
        .analyzerParams(analyzerParams) // Specifies the analyzer configuration
        .enableMatch(true)              // Enables inverted indexing for phrase matching
        .build());
// Define analyzer parameters for English-language tokenization
analyzerParams := map[string]any{"type": "english"}

// Add the VARCHAR field with the English analyzer enabled
schema.WithField(entity.NewField().
    WithName("text").                      // Name of the field
    WithDataType(entity.FieldTypeVarChar). // Field data type set as VARCHAR
    WithMaxLength(1000).                   // Maximum length of the string
    WithEnableAnalyzer(true).              // Enables text analysis
    WithAnalyzerParams(analyzerParams).    // Specifies the analyzer configuration
    WithEnableMatch(true),                 // Enables inverted indexing for phrase matching
)
// Define analyzer parameters for English-language tokenization
const analyzer_params = { type: "english" };

// Add the VARCHAR field with the English analyzer enabled
const schema = [
  {
    name: "text", // Name of the field
    data_type: DataType.VarChar, // Field data type set as VARCHAR
    max_length: 1000, // Maximum length of the string
    enable_analyzer: true, // Enables text analysis
    analyzer_params: analyzer_params, // Specifies the analyzer configuration
    enable_match: true, // Enables inverted indexing for phrase matching
  },
];
export schema='{
        "autoId": true,
        "enabledDynamicField": false,
        "fields": [
            {
                "fieldName": "text",
                "dataType": "VarChar",
                "elementTypeParams": {
                    "max_length": 1000,
                    "enable_analyzer": true,
                    "analyzer_params": {"type": "english"},
                    "enable_match": true
                }
            }
        ]
    }'
// Define analyzer parameters for English-language tokenization
nlohmann::json analyzer_params = {{"type", "english"}};

// Add the VARCHAR field with the English analyzer enabled
schema.AddField(milvus::FieldSchema("text", milvus::DataType::VARCHAR)  // Name of the field
                    .WithMaxLength(1000)                // Maximum length of the string
                    .EnableAnalyzer(true)               // Enables text analysis
                    .WithAnalyzerParams(analyzer_params) // Specifies the analyzer configuration
                    .EnableMatch(true));                // Enables inverted indexing for phrase matching

Milvus поддерживает несколько анализаторов, адаптированных для различных языков и сценариев использования. Подробную информацию см. в разделе «Обзор анализаторов».

Использование поиска по фразам

После включения сопоставления для поля VARCHAR в схеме коллекции можно выполнять сопоставление фраз с помощью выражения PHRASE_MATCH.

В выражении « PHRASE_MATCH » не учитывается регистр. Можно использовать как « PHRASE_MATCH », так и « phrase_match ».

Синтаксис выражения PHRASE_MATCH

Используйте выражение « PHRASE_MATCH » для указания поля, фразы и опциональной гибкости (slop) при поиске. Синтаксис следующий:

PHRASE_MATCH(field_name, phrase, slop)
PHRASE_MATCH(field_name, phrase, slop)
PHRASE_MATCH(field_name, phrase, slop)
PHRASE_MATCH(field_name, phrase, slop)
PHRASE_MATCH(field_name, phrase, slop)
PHRASE_MATCH(field_name, phrase, slop)
  • field_name: Имя поля « VARCHAR », по которому выполняется поиск по фразе.

  • phrase: Точная фраза, которую нужно найти.

  • slop (необязательно): Целое число, указывающее максимальное количество позиций, допускаемых в совпадающих токенах.

    • 0 (по умолчанию): Соответствует только точным фразам. Пример: Фильтр для «machine learning» будет соответствовать именно «machine learning», но не «machine boosts learning» или «learning machine».

    • 1: Допускает незначительные вариации, такие как один дополнительный термин или небольшое смещение позиции. Пример: фильтр для «machine learning» найдет совпадение с «machine boosts learning» (один токен между «machine» и «learning»), но не с «learning machine» (термины в обратном порядке).

    • 2: Допускает большую гибкость, включая обратный порядок терминов или до двух токенов между ними. Пример: Фильтр по запросу «machine learning» будет находить совпадения с «learning machine» (термины в обратном порядке) или «machine quickly boosts learning» (два токена между «machine» и «learning»).

Пример набора данных

Предположим, у вас есть коллекция с именем tech_articles, содержащая следующие пять сущностей:

doc_id

text

1

«Машинное обучение повышает эффективность анализа больших массивов данных»

2

«Освоение машинного подхода имеет жизненно важное значение для прогресса современного искусственного интеллекта»

3

«Архитектуры систем глубокого обучения оптимизируют вычислительную нагрузку»

4

«Машина быстро улучшает производительность модели для непрерывного обучения»

5

«Обучение сложным алгоритмам расширяет возможности ИИ»

Запрос с сопоставлением фразы

При использовании метода query() параметр PHRASE_MATCH действует как скалярный фильтр. Возвращаются только те документы, которые содержат указанную фразу (с учетом допустимого отклонения).

Пример: slop = 0 (точное совпадение)

В этом примере возвращаются документы, содержащие точную фразу «machine learning» без каких-либо дополнительных токенов между словами.

# Match documents containing exactly "machine learning"
filter = "PHRASE_MATCH(text, 'machine learning')"

result = client.query(
    collection_name="tech_articles",
    filter=filter,
    output_fields=["id", "text"]
)
// Match documents containing exactly "machine learning"
String filter = "PHRASE_MATCH(text, 'machine learning')";

QueryResp queryResp = client.query(QueryReq.builder()
        .collectionName("tech_articles")
        .filter(filter)
        .outputFields(Arrays.asList("id", "text"))
        .build());
// Match documents containing exactly "machine learning"
filter := "PHRASE_MATCH(text, 'machine learning')"

resultSet, err := client.Query(ctx, milvusclient.NewQueryOption("tech_articles").
    WithFilter(filter).
    WithOutputFields("id", "text"))
if err != nil {
    fmt.Println(err.Error())
    // handle error
}
// Match documents containing exactly "machine learning"
const filter = "PHRASE_MATCH(text, 'machine learning')";

const result = await client.query({
    collection_name: "tech_articles",
    filter: filter,
    output_fields: ["id", "text"],
});
export filter="\"PHRASE_MATCH(text, 'machine learning')\""

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": "tech_articles",
    "filter": '"$filter"',
    "outputFields": ["id", "text"]
}'
// Match documents containing exactly "machine learning"
milvus::QueryResponse response;
auto status = client->Query(milvus::QueryRequest()
                                .WithCollectionName("tech_articles")
                                .WithFilter("PHRASE_MATCH(text, 'machine learning')")
                                .AddOutputField("id")
                                .AddOutputField("text"),
                            response);
if (!status.IsOk()) {
    std::cout << status.Message() << std::endl;
}

Ожидаемые результаты поиска:

doc_id

text

1

«Машинное обучение повышает эффективность анализа больших массивов данных»

Только документ 1 содержит точную фразу «machine learning» в указанном порядке без дополнительных токенов.

Поиск с помощью фразового сопоставления

В поисковых операциях PHRASE_MATCH используется для фильтрации документов перед применением ранжирования по векторному сходству. Этот двухэтапный подход сначала сужает набор кандидатов с помощью текстового сопоставления, а затем заново ранжирует этих кандидатов на основе векторных вложений.

Пример: slop = 1

Здесь мы допускаем погрешность (slop) равную 1. Фильтр применяется к документам, содержащим фразу «learning machine», с небольшой гибкостью.

# Example: Filter documents containing "learning machine" with slop=1
filter_slop1 = "PHRASE_MATCH(text, 'learning machine', 1)"

result_slop1 = client.search(
    collection_name="tech_articles",
    anns_field="embeddings",
    data=[query_vector],
    filter=filter_slop1,
    search_params={"params": {"nprobe": 10}},
    limit=10,
    output_fields=["id", "text"]
)
// Example: Filter documents containing "learning machine" with slop=1
String filter = "PHRASE_MATCH(text, 'learning machine', 1)";

Map<String, Object> searchParams = new HashMap<>();
searchParams.put("nprobe", 10);

SearchResp searchResp = client.search(SearchReq.builder()
        .collectionName("tech_articles")
        .annsField("embeddings")
        .data(Collections.singletonList(queryVector))
        .filter(filter)
        .searchParams(searchParams)
        .topK(10)
        .outputFields(Arrays.asList("id", "text"))
        .build());
// Example: Filter documents containing "learning machine" with slop=1
filter := "PHRASE_MATCH(text, 'learning machine', 1)"

resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
    "tech_articles", // collectionName
    10,              // limit
    []entity.Vector{entity.FloatVector(queryVector)},
).WithANNSField("embeddings").
    WithFilter(filter).
    WithSearchParam("nprobe", "10").
    WithOutputFields("id", "text"))
if err != nil {
    fmt.Println(err.Error())
    // handle error
}
// Example: Filter documents containing "learning machine" with slop=1
const filter = "PHRASE_MATCH(text, 'learning machine', 1)";

const result = await client.search({
    collection_name: "tech_articles",
    anns_field: "embeddings",
    data: [query_vector],
    filter: filter,
    params: { nprobe: 10 },
    limit: 10,
    output_fields: ["id", "text"],
});
export filter="\"PHRASE_MATCH(text, 'learning machine', 1)\""

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": "tech_articles",
    "annsField": "embeddings",
    "data": [[0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104]],
    "filter": '"$filter"',
    "searchParams": {
        "params": {
            "nprobe": 10
        }
    },
    "limit": 10,
    "outputFields": ["id", "text"]
}'
// Example: Filter documents containing "learning machine" with slop=1
milvus::SearchResponse response;
auto status = client->Search(milvus::SearchRequest()
                                 .WithCollectionName("tech_articles")
                                 .WithAnnsField("embeddings")
                                 .AddFloatVector(query_vector)
                                 .WithFilter("PHRASE_MATCH(text, 'learning machine', 1)")
                                 .AddExtraParam("nprobe", "10")
                                 .WithLimit(10)
                                 .AddOutputField("id")
                                 .AddOutputField("text"),
                             response);
if (!status.IsOk()) {
    std::cout << status.Message() << std::endl;
}

Результаты сопоставления:

doc_id

text

2

«Изучение машинного подхода имеет жизненно важное значение для прогресса современного ИИ»

3

«Архитектуры систем глубокого обучения оптимизируют вычислительную нагрузку»

5

«Освоение передовых алгоритмов машинного обучения расширяет возможности искусственного интеллекта»

Пример: slop = 2

В этом примере допускается отклонение 2, что означает, что между словами «machine» и «learning» допускается до двух дополнительных токенов (или терминов в обратном порядке) .

# Example: Filter documents containing "machine learning" with slop=2
filter_slop2 = "PHRASE_MATCH(text, 'machine learning', 2)"

result_slop2 = client.search(
    collection_name="tech_articles",
    anns_field="embeddings",             # Vector field name
    data=[query_vector],                 # Query vector
    filter=filter_slop2,                 # Filter expression
    search_params={"params": {"nprobe": 10}},
    limit=10,                            # Maximum results to return
    output_fields=["id", "text"]
)
// Example: Filter documents containing "machine learning" with slop=2
String filter = "PHRASE_MATCH(text, 'machine learning', 2)";

Map<String, Object> searchParams = new HashMap<>();
searchParams.put("nprobe", 10);

SearchResp searchResp = client.search(SearchReq.builder()
        .collectionName("tech_articles")
        .annsField("embeddings")            // Vector field name
        .data(Collections.singletonList(queryVector)) // Query vector
        .filter(filter)                     // Filter expression
        .searchParams(searchParams)
        .topK(10)                           // Maximum results to return
        .outputFields(Arrays.asList("id", "text"))
        .build());
// Example: Filter documents containing "machine learning" with slop=2
filter := "PHRASE_MATCH(text, 'machine learning', 2)"

resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
    "tech_articles", // collectionName
    10,              // limit, maximum results to return
    []entity.Vector{entity.FloatVector(queryVector)}, // query vector
).WithANNSField("embeddings"). // vector field name
    WithFilter(filter).        // filter expression
    WithSearchParam("nprobe", "10").
    WithOutputFields("id", "text"))
if err != nil {
    fmt.Println(err.Error())
    // handle error
}
// Example: Filter documents containing "machine learning" with slop=2
const filter = "PHRASE_MATCH(text, 'machine learning', 2)";

const result = await client.search({
    collection_name: "tech_articles",
    anns_field: "embeddings", // Vector field name
    data: [query_vector], // Query vector
    filter: filter, // Filter expression
    params: { nprobe: 10 },
    limit: 10, // Maximum results to return
    output_fields: ["id", "text"],
});
export filter="\"PHRASE_MATCH(text, 'machine learning', 2)\""

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": "tech_articles",
    "annsField": "embeddings",
    "data": [[0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104]],
    "filter": '"$filter"',
    "searchParams": {
        "params": {
            "nprobe": 10
        }
    },
    "limit": 10,
    "outputFields": ["id", "text"]
}'
// Example: Filter documents containing "machine learning" with slop=2
milvus::SearchResponse response;
auto status = client->Search(milvus::SearchRequest()
                                 .WithCollectionName("tech_articles")
                                 .WithAnnsField("embeddings") // Vector field name
                                 .AddFloatVector(query_vector) // Query vector
                                 .WithFilter("PHRASE_MATCH(text, 'machine learning', 2)") // Filter expression
                                 .AddExtraParam("nprobe", "10")
                                 .WithLimit(10) // Maximum results to return
                                 .AddOutputField("id")
                                 .AddOutputField("text"),
                             response);
if (!status.IsOk()) {
    std::cout << status.Message() << std::endl;
}

Результаты поиска:

doc_id

text

1

«Машинное обучение повышает эффективность анализа больших массивов данных»

3

«Архитектуры систем глубокого обучения оптимизируют вычислительную нагрузку»

Пример: slop = 3

В этом примере значение slop, равное 3, обеспечивает ещё большую гибкость. Фильтр ищет фразу «machine learning», при этом между словами допускается до трёх позиций токенов.

# Example: Filter documents containing "machine learning" with slop=3
filter_slop3 = "PHRASE_MATCH(text, 'machine learning', 3)"

result_slop2 = client.search(
    collection_name="tech_articles",
    anns_field="embeddings",             # Vector field name
    data=[query_vector],                 # Query vector
    filter=filter_slop3,                 # Filter expression
    search_params={"params": {"nprobe": 10}},
    limit=10,                            # Maximum results to return
    output_fields=["id", "text"]
)
// Example: Filter documents containing "machine learning" with slop=3
String filter = "PHRASE_MATCH(text, 'machine learning', 3)";

Map<String, Object> searchParams = new HashMap<>();
searchParams.put("nprobe", 10);

SearchResp searchResp = client.search(SearchReq.builder()
        .collectionName("tech_articles")
        .annsField("embeddings")            // Vector field name
        .data(Collections.singletonList(queryVector)) // Query vector
        .filter(filter)                     // Filter expression
        .searchParams(searchParams)
        .topK(10)                           // Maximum results to return
        .outputFields(Arrays.asList("id", "text"))
        .build());
// Example: Filter documents containing "machine learning" with slop=3
filter := "PHRASE_MATCH(text, 'machine learning', 3)"

resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
    "tech_articles", // collectionName
    10,              // limit, maximum results to return
    []entity.Vector{entity.FloatVector(queryVector)}, // query vector
).WithANNSField("embeddings"). // vector field name
    WithFilter(filter).        // filter expression
    WithSearchParam("nprobe", "10").
    WithOutputFields("id", "text"))
if err != nil {
    fmt.Println(err.Error())
    // handle error
}
// Example: Filter documents containing "machine learning" with slop=3
const filter = "PHRASE_MATCH(text, 'machine learning', 3)";

const result = await client.search({
    collection_name: "tech_articles",
    anns_field: "embeddings", // Vector field name
    data: [query_vector], // Query vector
    filter: filter, // Filter expression
    params: { nprobe: 10 },
    limit: 10, // Maximum results to return
    output_fields: ["id", "text"],
});
export filter="\"PHRASE_MATCH(text, 'machine learning', 3)\""

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": "tech_articles",
    "annsField": "embeddings",
    "data": [[0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104]],
    "filter": '"$filter"',
    "searchParams": {
        "params": {
            "nprobe": 10
        }
    },
    "limit": 10,
    "outputFields": ["id", "text"]
}'
// Example: Filter documents containing "machine learning" with slop=3
milvus::SearchResponse response;
auto status = client->Search(milvus::SearchRequest()
                                 .WithCollectionName("tech_articles")
                                 .WithAnnsField("embeddings") // Vector field name
                                 .AddFloatVector(query_vector) // Query vector
                                 .WithFilter("PHRASE_MATCH(text, 'machine learning', 3)") // Filter expression
                                 .AddExtraParam("nprobe", "10")
                                 .WithLimit(10) // Maximum results to return
                                 .AddOutputField("id")
                                 .AddOutputField("text"),
                             response);
if (!status.IsOk()) {
    std::cout << status.Message() << std::endl;
}

Результаты поиска:

doc_id

text

1

«Машинное обучение повышает эффективность анализа больших массивов данных»

2

«Изучение машинного подхода имеет жизненно важное значение для прогресса современного ИИ»

3

«Архитектуры систем глубокого обучения оптимизируют вычислительную нагрузку»

5

«Изучение передовых алгоритмов машинного обучения расширяет возможности ИИ»

Рекомендации

  • Включение сопоставления фраз для поля приводит к созданию инвертированного индекса, что требует ресурсов хранения. При принятии решения о включении этой функции учитывайте влияние на хранение, поскольку оно зависит от размера текста, количества уникальных токенов и используемого анализатора.

  • После определения анализатора в схеме его настройки становятся постоянными для данной коллекции. Если вы решите, что другой анализатор лучше соответствует вашим потребностям, можно удалить существующую коллекцию и создать новую с нужной конфигурацией анализатора.

  • Производительность поиска по фразам зависит от способа токенизации текста. Прежде чем применять анализатор ко всей коллекции, воспользуйтесь методом ` run_analyzer `, чтобы проверить результаты токенизации. Дополнительные сведения см. в разделе «Обзор анализаторов».

  • Правила экранирования в выражениях filter:

    • Символы, заключённые в двойные или одинарные кавычки внутри выражений, интерпретируются как строковые константы. Если строковая константа содержит символы экранирования, они должны быть представлены с помощью экранирующих последовательностей. Например, используйте ` \\ ` для представления \, ` \\t ` — для табуляции \t, а ` \\n ` — для символа новой строки.

    • Если строковая константа заключена в одинарные кавычки, одинарная кавычка внутри константы должна представляться как \\', тогда как двойная кавычка может представляться либо как ", либо как \\". Пример: 'It\\'s milvus'.

    • Если строковая константа заключена в двойные кавычки, двойная кавычка внутри константы должна быть представлена как \\", а одинарная кавычка может быть представлена либо как ', либо как \\'. Пример: "He said \\"Hi\\"".