milvus/internal/util/textmatch/phrase_match.go
Spade A ad8aba7cb4
feat: impl ComputePhraseMatchSlop for compute min slop for phrase match query (#45892)
issue: https://github.com/milvus-io/milvus/issues/45890

ComputePhraseMatchSlop accepts three pararms:
1. A string: query text
2. Some trings: data texts
3. Analyzer params,

Slop will be calculated for the query text with each data text in the
context of phrase match where they are tokenized with tokenizer with
analyzer params.

So two array will be returned:
1. is_match: is phrase match can sucess
2. slop: the related slop if phrase match can sucess, or -1 is cannot.

---------

Signed-off-by: SpadeA <tangchenjie1210@gmail.com>
2025-12-19 16:03:18 +08:00

67 lines
1.8 KiB
Go

package textmatch
/*
#cgo pkg-config: milvus_core
#include <stdlib.h>
#include "segcore/phrase_match_c.h"
*/
import "C"
import (
"fmt"
"unsafe"
"github.com/milvus-io/milvus/pkg/v2/log"
"github.com/milvus-io/milvus/pkg/v2/util/merr"
)
// Error codes from C++ segcore (internal/core/output/include/common/EasyAssert.h)
const (
errCodeUnsupported = 2003 // Unsupported operation
errCodeClusterSkip = 2033 // ClusterSkip - pretend finished
)
// ComputePhraseMatchSlop computes the minimum slop required for a phrase match
// between query and data texts using the specified analyzer.
// Returns the slop value if match is possible, or error if terms are missing.
func ComputePhraseMatchSlop(analyzerParams string, query string, data string) (int32, error) {
cParams := C.CString(analyzerParams)
defer C.free(unsafe.Pointer(cParams))
cQuery := C.CString(query)
defer C.free(unsafe.Pointer(cQuery))
cData := C.CString(data)
defer C.free(unsafe.Pointer(cData))
var slop C.uint32_t
status := C.compute_phrase_match_slop_c(cParams, cQuery, cData, &slop)
if err := handleCStatus(&status, "failed to compute phrase match slop"); err != nil {
return 0, err
}
return int32(slop), nil
}
// handleCStatus deals with the error returned from CGO
func handleCStatus(status *C.CStatus, extraInfo string) error {
if status.error_code == 0 {
return nil
}
errorCode := int(status.error_code)
errorMsg := C.GoString(status.error_msg)
defer C.free(unsafe.Pointer(status.error_msg))
logMsg := fmt.Sprintf("%s, C Runtime Exception: %s\n", extraInfo, errorMsg)
log.Warn(logMsg)
if errorCode == 2003 {
return merr.WrapErrSegcoreUnsupported(int32(errorCode), logMsg)
}
if errorCode == 2033 {
log.Info("fake finished the task")
return merr.ErrSegcorePretendFinished
}
return merr.WrapErrSegcore(int32(errorCode), logMsg)
}