github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/shard_write_inverted_lsm_delete.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 package db 13 14 import ( 15 "encoding/binary" 16 "fmt" 17 18 "github.com/pkg/errors" 19 "github.com/weaviate/weaviate/adapters/repos/db/helpers" 20 "github.com/weaviate/weaviate/adapters/repos/db/inverted" 21 "github.com/weaviate/weaviate/adapters/repos/db/lsmkv" 22 ) 23 24 func (s *Shard) deleteFromInvertedIndicesLSM(props []inverted.Property, nilProps []inverted.NilProperty, 25 docID uint64, 26 ) error { 27 for _, prop := range props { 28 if prop.HasFilterableIndex { 29 bucket := s.store.Bucket(helpers.BucketFromPropNameLSM(prop.Name)) 30 if bucket == nil { 31 return fmt.Errorf("no bucket for prop '%s' found", prop.Name) 32 } 33 34 for _, item := range prop.Items { 35 if err := s.deleteFromPropertySetBucket(bucket, docID, item.Data); err != nil { 36 return errors.Wrapf(err, "delete item '%s' from index", 37 string(item.Data)) 38 } 39 } 40 } 41 42 if prop.HasSearchableIndex { 43 bucket := s.store.Bucket(helpers.BucketSearchableFromPropNameLSM(prop.Name)) 44 if bucket == nil { 45 return fmt.Errorf("no bucket searchable for prop '%s' found", prop.Name) 46 } 47 48 for _, item := range prop.Items { 49 if err := s.deleteInvertedIndexItemWithFrequencyLSM(bucket, item, 50 docID); err != nil { 51 return errors.Wrapf(err, "delete item '%s' from index", 52 string(item.Data)) 53 } 54 } 55 } 56 57 // add non-nil properties to the null-state inverted index, but skip internal properties (__meta_count, _id etc) 58 if isMetaCountProperty(prop) || isInternalProperty(prop) { 59 continue 60 } 61 62 // properties where defining a length does not make sense (floats etc.) have a negative entry as length 63 if s.index.invertedIndexConfig.IndexPropertyLength && prop.Length >= 0 { 64 if err := s.deleteFromPropertyLengthIndex(prop.Name, docID, prop.Length); err != nil { 65 return errors.Wrap(err, "add indexed property length") 66 } 67 } 68 69 if s.index.invertedIndexConfig.IndexNullState { 70 if err := s.deleteFromPropertyNullIndex(prop.Name, docID, prop.Length == 0); err != nil { 71 return errors.Wrap(err, "add indexed null state") 72 } 73 } 74 } 75 76 // remove nil properties from the nullstate and property length inverted index 77 for _, nilProperty := range nilProps { 78 if s.index.invertedIndexConfig.IndexPropertyLength && nilProperty.AddToPropertyLength { 79 if err := s.deleteFromPropertyLengthIndex(nilProperty.Name, docID, 0); err != nil { 80 return errors.Wrap(err, "add indexed property length") 81 } 82 } 83 84 if s.index.invertedIndexConfig.IndexNullState { 85 if err := s.deleteFromPropertyNullIndex(nilProperty.Name, docID, true); err != nil { 86 return errors.Wrap(err, "add indexed null state") 87 } 88 } 89 } 90 91 return nil 92 } 93 94 func (s *Shard) deleteInvertedIndexItemWithFrequencyLSM(bucket *lsmkv.Bucket, 95 item inverted.Countable, docID uint64, 96 ) error { 97 lsmkv.CheckExpectedStrategy(bucket.Strategy(), lsmkv.StrategyMapCollection) 98 99 docIDBytes := make([]byte, 8) 100 // Shard Index version 2 requires BigEndian for sorting, if the shard was 101 // built prior assume it uses LittleEndian 102 if s.versioner.Version() < 2 { 103 binary.LittleEndian.PutUint64(docIDBytes, docID) 104 } else { 105 binary.BigEndian.PutUint64(docIDBytes, docID) 106 } 107 108 return bucket.MapDeleteKey(item.Data, docIDBytes) 109 } 110 111 func (s *Shard) deleteFromPropertyLengthIndex(propName string, docID uint64, length int) error { 112 bucketLength := s.store.Bucket(helpers.BucketFromPropNameLengthLSM(propName)) 113 if bucketLength == nil { 114 return errors.Errorf("no bucket for prop '%s' length found", propName) 115 } 116 117 key, err := bucketKeyPropertyLength(length) 118 if err != nil { 119 return errors.Wrapf(err, "failed creating key for prop '%s' length", propName) 120 } 121 if err := s.deleteFromPropertySetBucket(bucketLength, docID, key); err != nil { 122 return errors.Wrapf(err, "failed adding to prop '%s' length bucket", propName) 123 } 124 return nil 125 } 126 127 func (s *Shard) deleteFromPropertyNullIndex(propName string, docID uint64, isNull bool) error { 128 bucketNull := s.store.Bucket(helpers.BucketFromPropNameNullLSM(propName)) 129 if bucketNull == nil { 130 return errors.Errorf("no bucket for prop '%s' null found", propName) 131 } 132 133 key, err := bucketKeyPropertyNull(isNull) 134 if err != nil { 135 return errors.Wrapf(err, "failed creating key for prop '%s' null", propName) 136 } 137 if err := s.deleteFromPropertySetBucket(bucketNull, docID, key); err != nil { 138 return errors.Wrapf(err, "failed adding to prop '%s' null bucket", propName) 139 } 140 return nil 141 } 142 143 func (s *Shard) deleteFromPropertySetBucket(bucket *lsmkv.Bucket, docID uint64, key []byte) error { 144 lsmkv.CheckExpectedStrategy(bucket.Strategy(), lsmkv.StrategySetCollection, lsmkv.StrategyRoaringSet) 145 146 if bucket.Strategy() == lsmkv.StrategySetCollection { 147 docIDBytes := make([]byte, 8) 148 binary.LittleEndian.PutUint64(docIDBytes, docID) 149 150 return bucket.SetDeleteSingle(key, docIDBytes) 151 } 152 153 return bucket.RoaringSetRemoveOne(key, docID) 154 }