项目文件夹

文件
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

92 行
3.5 KiB
Go

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
package search
import (
"os"
"strings"
"unicode"
porterstemmer "github.com/blevesearch/go-porterstemmer"
)
// ftsStemmingEnabled gates the token-normalization pass — stopword
// removal plus Porter stemming — applied to the full-text-search index
// and query paths. Default OFF: on the recall fixture stemming trades
// exact-symbol-lookup precision (exact-tier R@5 3.1pp) for broader
// recall (R@20 +5.7pp), so it ships as an opt-in rather than quietly
// reranking every identifier query. Enable it with
// GORTEX_FTS_STEMMING=1 (also true / yes / on).
//
// Read once at process start, like the bigram-typo flag: the index
// built during a daemon's lifetime and every query against it share a
// single setting, so a mid-session toggle can't desynchronise stemmed
// postings from stemmed query terms. When enabled, the same
// normalization runs on both the posting list and the query, so the
// two never disagree.
var ftsStemmingEnabled = ftsStemmingFromEnv()
func ftsStemmingFromEnv() bool {
switch strings.ToLower(strings.TrimSpace(os.Getenv("GORTEX_FTS_STEMMING"))) {
case "1", "true", "yes", "on", "y":
return true
}
return false
}
// ftsStopWords is the stopword set: English glue words that carry
// no code-search signal. Deliberately tight — it holds only unambiguous
// function words, never code keywords (for / if / case / switch / type)
// or code-meaningful nouns (get / set / new / value / key), so dropping
// a member can never erase intent from a query. Tokens arrive already
// lowercased from Tokenize / TokenizeQuery.
var ftsStopWords = map[string]struct{}{
"the": {}, "a": {}, "an": {}, "and": {}, "or": {}, "but": {},
"of": {}, "to": {}, "in": {}, "on": {}, "at": {}, "by": {},
"with": {}, "as": {}, "is": {}, "are": {}, "was": {}, "were": {},
"be": {}, "been": {}, "that": {}, "this": {}, "these": {},
"those": {}, "from": {}, "into": {}, "than": {}, "then": {},
"it": {}, "its": {}, "so": {}, "such": {}, "via": {}, "per": {},
}
// NormalizeFTSTokens applies the FR63 stopword filter and Porter stemmer
// to a token list produced by Tokenize / TokenizeQuery. The index path
// (BM25Backend.Add, BleveBackend.Add) and the query path
// (BM25Backend.Search, BleveBackend.Search) both call it, so a stemmed
// posting list is always probed with stemmed query terms.
//
// Stopwords are dropped before stemming so a stemmed form can never
// collide with a stopword entry. The result is a freshly allocated
// slice; the input is left untouched. When stemming is disabled the
// input slice is returned unchanged.
func NormalizeFTSTokens(tokens []string) []string {
if !ftsStemmingEnabled || len(tokens) == 0 {
return tokens
}
out := make([]string, 0, len(tokens))
for _, t := range tokens {
if _, stop := ftsStopWords[t]; stop {
continue
}
out = append(out, stemFTSToken(t))
}
return out
}
// stemFTSToken returns the Porter stem of one lowercase token. Tokens
// shorter than four runes are returned unchanged — Porter's measure-
// gated rules almost never fire that low, and the trailing-"s" rule
// that does would conflate distinct short code fragments (ids vs id).
// Tokens carrying a digit or any non-ASCII rune are returned verbatim:
// the Porter algorithm is defined over the English letter alphabet, so
// "sha256" or "utf8" must not be mangled.
func stemFTSToken(t string) string {
if len(t) < 4 {
return t
}
for _, r := range t {
if r > unicode.MaxASCII || !unicode.IsLetter(r) {
return t
}
}
return porterstemmer.StemString(t)
}