snapshot of https://github.com/blevesearch/bleve.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
Coverage / coverage (push) Failing after 6s
Tests / test (1.24.x, ubuntu-latest) (push) Failing after 42s
Tests / test (1.26.x, ubuntu-latest) (push) Failing after 38s
Tests / test (1.25.x, ubuntu-latest) (push) Failing after 35s
Tests / test (1.25.x, windows-latest) (push) Has been cancelled
Tests / test (1.26.x, macos-latest) (push) Has been cancelled
Tests / test (1.26.x, windows-latest) (push) Has been cancelled
Tests / test (1.24.x, macos-latest) (push) Has been cancelled
Tests / test (1.24.x, windows-latest) (push) Has been cancelled
Tests / test (1.25.x, macos-latest) (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-15 22:27:16 +05:00
commit f8d3d9f0cf
797 changed files with 159570 additions and 0 deletions

View File

@@ -0,0 +1,137 @@
// Copyright (c) 2026 Couchbase, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package query
import (
"context"
"encoding/json"
"fmt"
"github.com/blevesearch/bleve/v2/mapping"
"github.com/blevesearch/bleve/v2/search"
"github.com/blevesearch/bleve/v2/search/searcher"
index "github.com/blevesearch/bleve_index_api"
)
// CustomScoreQuery wraps a child query and re-scores its candidate matches via
// an embedder-provided per-hit callback.
type CustomScoreQuery struct {
Query Query `json:"query"`
Fields []string `json:"fields,omitempty"`
scoreFunc searcher.CustomScoreFunc
payload map[string]interface{}
}
// CustomScoreQueryParser lets an embedder override parsing of
// {"custom_score": ...} nodes. It is intended to be assigned once during
// process startup or init, before any queries are parsed; callers must not
// mutate it concurrently with ParseQuery(). For example:
//
// func init() {
// query.CustomScoreQueryParser = parseCustomScoreQuery
// }
var CustomScoreQueryParser func([]byte) (Query, error)
func NewCustomScoreQueryWithScorer(query Query, score searcher.CustomScoreFunc, fields []string, payload map[string]interface{}) *CustomScoreQuery {
return &CustomScoreQuery{
Query: query,
Fields: fields,
scoreFunc: score,
payload: payload,
}
}
func (q *CustomScoreQuery) Searcher(ctx context.Context, i index.IndexReader, m mapping.IndexMapping, options search.SearcherOptions) (search.Searcher, error) {
if q == nil {
return nil, fmt.Errorf("custom score query is nil")
}
if q.Query == nil {
return nil, fmt.Errorf("custom score query must have a query")
}
if q.scoreFunc == nil {
return nil, fmt.Errorf("custom score query must have a score callback")
}
// Build the inner searcher first; custom scoring wraps its output.
childSearcher, err := q.Query.Searcher(ctx, i, m, options)
if err != nil {
return nil, err
}
// Create a doc value reader for the requested fields (if any) so the
// searcher can populate d.Fields before invoking the callback.
var dvReader index.DocValueReader
var fieldTypes map[string]string
if len(q.Fields) > 0 {
// Expand a "*" wildcard to the concrete field set; the doc-value
// reader matches field names literally and would otherwise load
// nothing, leaving d.Fields empty in the callback.
fields, err2 := expandFieldWildcard(q.Fields, i)
if err2 != nil {
_ = childSearcher.Close()
return nil, err2
}
dvReader, err2 = i.DocValueReader(fields)
if err2 != nil {
_ = childSearcher.Close()
return nil, err2
}
fieldTypes = resolveFieldTypes(fields, m)
}
return searcher.NewCustomScoreSearcher(ctx, childSearcher, q.scoreFunc, dvReader, i, fieldTypes, options.Explain), nil
}
func (q *CustomScoreQuery) Validate() error {
if q == nil {
return fmt.Errorf("custom score query is nil")
}
if q.Query == nil {
return fmt.Errorf("custom score query must have a query")
}
if q.scoreFunc == nil {
return fmt.Errorf("custom score query must have a score callback")
}
if vq, ok := q.Query.(ValidatableQuery); ok {
return vq.Validate()
}
return nil
}
func (q *CustomScoreQuery) MarshalJSON() ([]byte, error) {
inner := make(map[string]interface{}, len(q.payload)+2)
for k, v := range q.payload {
inner[k] = v
}
inner["query"] = q.Query
if len(q.Fields) > 0 {
inner["fields"] = q.Fields
}
return json.Marshal(map[string]interface{}{
"custom_score": inner,
})
}
func (q *CustomScoreQuery) UnmarshalJSON(data []byte) error {
child, fields, payload, err := unmarshalCustomQueryPayload(data, "custom_score")
if err != nil {
return err
}
q.Query = child
q.Fields = fields
q.payload = payload
return nil
}