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