github.com/attic-labs/noms@v0.0.0-20210827224422-e5fa29d95e8b/samples/go/decent/lib/term_index.go (about) 1 // See: https://github.com/attic-labs/noms/issues/3808 2 // +build ignore 3 4 // Copyright 2017 Attic Labs, Inc. All rights reserved. 5 // Licensed under the Apache License, version 2.0: 6 // http://www.apache.org/licenses/LICENSE-2.0 7 8 package lib 9 10 import ( 11 "sync" 12 13 "github.com/attic-labs/noms/go/types" 14 ) 15 16 type TermIndex struct { 17 TermDocs types.Map 18 vrw types.ValueReadWriter 19 } 20 21 func NewTermIndex(vrw types.ValueReadWriter, TermDocs types.Map) TermIndex { 22 return TermIndex{TermDocs, vrw} 23 } 24 25 func (ti TermIndex) Edit() *TermIndexEditor { 26 return &TermIndexEditor{ti.TermDocs.Edit(), ti.vrw} 27 } 28 29 func (ti TermIndex) Search(terms []string) types.Map { 30 seen := make(map[string]struct{}, len(terms)) 31 iters := make([]types.SetIterator, 0, len(terms)) 32 33 wg := sync.WaitGroup{} 34 idx := 0 35 for _, t := range terms { 36 if _, ok := seen[t]; ok { 37 continue 38 } 39 seen[t] = struct{}{} 40 41 iters = append(iters, nil) 42 i := idx 43 t := t 44 wg.Add(1) 45 go func() { 46 ts := ti.TermDocs.Get(types.String(t)) 47 if ts != nil { 48 iter := ts.(types.Set).Iterator() 49 iters[i] = iter 50 } 51 wg.Done() 52 }() 53 54 idx++ 55 } 56 wg.Wait() 57 58 var si types.SetIterator 59 for _, iter := range iters { 60 if iter == nil { 61 return types.NewMap(ti.vrw) // at least one term had no hits 62 } 63 64 if si == nil { 65 si = iter // first iter 66 continue 67 } 68 69 si = types.NewIntersectionIterator(si, iter) 70 } 71 72 ch := make(chan types.Value) 73 rch := types.NewStreamingMap(ti.vrw, ch) 74 for next := si.Next(); next != nil; next = si.Next() { 75 ch <- next 76 ch <- types.Bool(true) 77 } 78 close(ch) 79 80 return <-rch 81 } 82 83 type TermIndexEditor struct { 84 terms *types.MapEditor 85 vrw types.ValueReadWriter 86 } 87 88 // Builds a new TermIndex 89 func (te *TermIndexEditor) Value() TermIndex { 90 return TermIndex{te.terms.Map(), te.vrw} 91 } 92 93 // Indexes |v| by |term| 94 func (te *TermIndexEditor) Insert(term string, v types.Value) *TermIndexEditor { 95 tv := types.String(term) 96 hitSet := te.terms.Get(tv) 97 if hitSet == nil { 98 hitSet = types.NewSet(te.vrw) 99 } 100 hsEd, ok := hitSet.(*types.SetEditor) 101 if !ok { 102 hsEd = hitSet.(types.Set).Edit() 103 te.terms.Set(tv, hsEd) 104 } 105 106 hsEd.Insert(v) 107 return te 108 } 109 110 // Indexes |v| by each unique term in |terms| (tolerates duplicate terms) 111 func (te *TermIndexEditor) InsertAll(terms []string, v types.Value) *TermIndexEditor { 112 visited := map[string]struct{}{} 113 for _, term := range terms { 114 if _, ok := visited[term]; ok { 115 continue 116 } 117 visited[term] = struct{}{} 118 te.Insert(term, v) 119 } 120 return te 121 } 122 123 // TODO: te.Remove