mesh_search: filler words of a question (did, our, on, all) need not match, so the operator's own words find a tool; a query of filler finds nothing
mesh/delivery merged: source.main moved to novox/mesh-tools@a5097dc69ab2
mesh/check pass 9f25e5c9f6c1 on a5097dc69ab2 | carried from bb6a0e3192db | unit 116 run, 11 kept, 11 skipped | integration 118 run, 11 kept, 10 skippe…
mesh/delivery merged: source.main moved to novox/mesh-tools@a5097dc69ab2
mesh/check pass 9f25e5c9f6c1 on a5097dc69ab2 | carried from bb6a0e3192db | unit 116 run, 11 kept, 11 skipped | integration 118 run, 11 kept, 10 skippe…
This commit is contained in:
@@ -44,6 +44,31 @@ var synonyms = map[string][]string{
|
|||||||
"hosts": {"hostname"},
|
"hosts": {"hostname"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// filler are the function words a question carries and no tool is named for: a query's words must all
|
||||||
|
// match, so "did our weekly upgrade run on all our nodes" would otherwise find nothing for "did", "our",
|
||||||
|
// "on" and "all". Kept short and here only; a word that names something (`every`, `list`, `not`) is not
|
||||||
|
// in it. A query of nothing but these matches nothing.
|
||||||
|
var filler = map[string]bool{}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for _, w := range strings.Fields("a an the did do does our my your we i is are was on in at of for to all any and or with it its there what which how has have been") {
|
||||||
|
filler[w] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// queryWords are a query's words to match: split at spaces, the punctuation of a sentence trimmed from
|
||||||
|
// each end (`nodes?` is `nodes`), filler left out.
|
||||||
|
func queryWords(query string) []string {
|
||||||
|
var out []string
|
||||||
|
for _, w := range strings.Fields(query) {
|
||||||
|
w = strings.Trim(w, "?!.,;:\"'()")
|
||||||
|
if w != "" && !filler[w] {
|
||||||
|
out = append(out, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// hit is one match as mesh_search answers it.
|
// hit is one match as mesh_search answers it.
|
||||||
type hit struct {
|
type hit struct {
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
@@ -169,8 +194,11 @@ func scoreOf(query string, qwords []string, name, description string, replaces [
|
|||||||
// search is mesh_search's answer: every match, best first.
|
// search is mesh_search's answer: every match, best first.
|
||||||
func (x *index) search(query string) []hit {
|
func (x *index) search(query string) []hit {
|
||||||
query = strings.ToLower(strings.TrimSpace(query))
|
query = strings.ToLower(strings.TrimSpace(query))
|
||||||
qwords := strings.Fields(query)
|
qwords := queryWords(query)
|
||||||
var hits []hit
|
var hits []hit
|
||||||
|
if len(qwords) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
for _, st := range x.Seats {
|
for _, st := range x.Seats {
|
||||||
for _, v := range st.Verbs {
|
for _, v := range st.Verbs {
|
||||||
replaces := x.Replaces["seat:"+st.Seat+"."+v.Name]
|
replaces := x.Replaces["seat:"+st.Seat+"."+v.Name]
|
||||||
|
|||||||
@@ -149,3 +149,31 @@ func TestSearchWithoutReplacesMatchesAsBefore(t *testing.T) {
|
|||||||
t.Errorf("a tool's own name: %+v", hits)
|
t.Errorf("a tool's own name: %+v", hits)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A question's filler words do not have to match (every other word still does): the operator's own words
|
||||||
|
// find the tool whose description says it in other words; a query of filler alone finds nothing.
|
||||||
|
func TestSearchIgnoresFillerWords(t *testing.T) {
|
||||||
|
x := meshToSearch(t)
|
||||||
|
x.Modules["pacman"] = &moduleInfo{Module: "pacman", On: []string{"anchor"}, Tools: []Tool{{Module: "pacman", Name: "pacman_round",
|
||||||
|
Description: "Whether this week's system upgrade ran on every node (the weekly upgrade round, last run of all nodes)."}}}
|
||||||
|
for _, c := range []struct {
|
||||||
|
query string
|
||||||
|
want string // the first hit's address, "" for none
|
||||||
|
}{
|
||||||
|
{"did our weekly system upgrade run on all our nodes?", "anchor/pacman.pacman_round"},
|
||||||
|
{"the weekly upgrade", "anchor/pacman.pacman_round"},
|
||||||
|
{"did our", ""},
|
||||||
|
{"what is the", ""},
|
||||||
|
{"", ""},
|
||||||
|
{"did our weekly kubernetes upgrade run?", ""},
|
||||||
|
} {
|
||||||
|
hits := x.search(c.query)
|
||||||
|
got := ""
|
||||||
|
if len(hits) > 0 {
|
||||||
|
got = hits[0].Address
|
||||||
|
}
|
||||||
|
if got != c.want || (c.want == "" && len(hits) != 0) {
|
||||||
|
t.Errorf("%q: first hit %q, want %q (%+v)", c.query, got, c.want, hits)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user