mirror of
https://github.com/PeernetOfficial/core.git
synced 2026-07-19 03:27:50 +01:00
Search: Deduplication of file IDs if found via multiple search terms.
This commit is contained in:
@@ -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 ----
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user