Search: Deduplication of file IDs if found via multiple search terms.

This commit is contained in:
Kleissner
2021-12-13 04:02:17 +01:00
parent 359387af0d
commit 8c8a901a31
2 changed files with 34 additions and 24 deletions

View File

@@ -17,11 +17,17 @@ import (
"github.com/google/uuid"
)
// A search selector is a term that discovers a file.
type SearchSelector struct {
Word string // Normalized version of the word
Hash []byte // Hash of the word
ExactSearch bool // Indicates this is an exact search term, for example a full filename.
}
// SearchIndexRecord identifies a hash to a given file
type SearchIndexRecord struct {
// input data
Word string
Hash []byte
// List of selectors that found the result. Multiple keywords may find the same file.
Selectors []SearchSelector
// result data
FileID uuid.UUID
@@ -180,7 +186,7 @@ func (index *SearchIndexStore) UnindexHash(fileID uuid.UUID, hash []byte) (err e
}
// LookupHash returns all index records stored for the hash.
func (index *SearchIndexStore) LookupHash(hash []byte) (records []SearchIndexRecord, err error) {
func (index *SearchIndexStore) LookupHash(selector SearchSelector, resultMap map[uuid.UUID]*SearchIndexRecord) (err error) {
if index.Database == nil {
return
}
@@ -188,21 +194,25 @@ func (index *SearchIndexStore) LookupHash(hash []byte) (records []SearchIndexRec
index.RLock()
defer index.RUnlock()
raw, found := index.Database.Get(hash)
raw, found := index.Database.Get(selector.Hash)
if !found {
return nil, nil
return nil
} else if len(raw)%indexRecordSize != 0 { // check if record is corrupt
return nil, errors.New("corrupt index record")
return errors.New("corrupt index record")
}
for offset := 0; offset < len(raw); offset += indexRecordSize {
if record := decodeIndexRecord(raw[offset : offset+indexRecordSize]); record != nil {
record.Hash = hash
records = append(records, *record)
if existingRecord, ok := resultMap[record.FileID]; ok {
existingRecord.Selectors = append(existingRecord.Selectors, selector)
} else {
record.Selectors = []SearchSelector{selector}
resultMap[record.FileID] = record
}
}
}
return records, nil
return nil
}
// ---- index and reverse index code ----

View File

@@ -6,6 +6,8 @@ Author: Peter Kleissner
package search
import "github.com/google/uuid"
func (index *SearchIndexStore) Search(term string) (results []SearchIndexRecord) {
termS, isExact, _ := sanitizeInputTerm(term)
@@ -13,16 +15,23 @@ func (index *SearchIndexStore) Search(term string) (results []SearchIndexRecord)
return
}
resultMap := make(map[uuid.UUID]*SearchIndexRecord)
resultMapToSlice := func() (results []SearchIndexRecord) {
for _, result := range resultMap {
results = append(results, *result)
}
return results
}
// start with exact search
hashExact := hashWord(termS)
if hashExact != nil {
records, _ := index.LookupHash(hashExact)
results = append(results, setSearchIndexFields(records, termS)...)
index.LookupHash(SearchSelector{Hash: hashExact, Word: termS, ExactSearch: true}, resultMap)
}
// exact search only?
if isExact {
return
return resultMapToSlice()
}
// break up the term into hashes
@@ -35,17 +44,8 @@ func (index *SearchIndexStore) Search(term string) (results []SearchIndexRecord)
// look up the hashes!
for hash, keyword := range hashes {
records, _ := index.LookupHash(hash[:])
results = append(results, setSearchIndexFields(records, keyword)...)
index.LookupHash(SearchSelector{Hash: hash[:], Word: keyword}, resultMap)
}
return
}
// setSearchIndexFields sets certain fields in the index record for adding context in the output
func setSearchIndexFields(records []SearchIndexRecord, word string) []SearchIndexRecord {
for n := range records {
records[n].Word = word
}
return records
return resultMapToSlice()
}