github.com/haalcala/mattermost-server-change-repo/v5@v5.33.2/services/searchengine/bleveengine/bleve.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package bleveengine 5 6 import ( 7 "net/http" 8 "os" 9 "path/filepath" 10 "sync" 11 "sync/atomic" 12 "time" 13 14 "github.com/blevesearch/bleve" 15 "github.com/blevesearch/bleve/analysis/analyzer/keyword" 16 "github.com/blevesearch/bleve/analysis/analyzer/standard" 17 "github.com/blevesearch/bleve/mapping" 18 19 "github.com/mattermost/mattermost-server/v5/jobs" 20 "github.com/mattermost/mattermost-server/v5/mlog" 21 "github.com/mattermost/mattermost-server/v5/model" 22 ) 23 24 const ( 25 EngineName = "bleve" 26 PostIndex = "posts" 27 FileIndex = "files" 28 UserIndex = "users" 29 ChannelIndex = "channels" 30 ) 31 32 type BleveEngine struct { 33 PostIndex bleve.Index 34 FileIndex bleve.Index 35 UserIndex bleve.Index 36 ChannelIndex bleve.Index 37 Mutex sync.RWMutex 38 ready int32 39 cfg *model.Config 40 jobServer *jobs.JobServer 41 indexSync bool 42 } 43 44 var keywordMapping *mapping.FieldMapping 45 var standardMapping *mapping.FieldMapping 46 var dateMapping *mapping.FieldMapping 47 48 func init() { 49 keywordMapping = bleve.NewTextFieldMapping() 50 keywordMapping.Analyzer = keyword.Name 51 52 standardMapping = bleve.NewTextFieldMapping() 53 standardMapping.Analyzer = standard.Name 54 55 dateMapping = bleve.NewNumericFieldMapping() 56 } 57 58 func getChannelIndexMapping() *mapping.IndexMappingImpl { 59 channelMapping := bleve.NewDocumentMapping() 60 channelMapping.AddFieldMappingsAt("Id", keywordMapping) 61 channelMapping.AddFieldMappingsAt("TeamId", keywordMapping) 62 channelMapping.AddFieldMappingsAt("NameSuggest", keywordMapping) 63 64 indexMapping := bleve.NewIndexMapping() 65 indexMapping.AddDocumentMapping("_default", channelMapping) 66 67 return indexMapping 68 } 69 70 func getPostIndexMapping() *mapping.IndexMappingImpl { 71 postMapping := bleve.NewDocumentMapping() 72 postMapping.AddFieldMappingsAt("Id", keywordMapping) 73 postMapping.AddFieldMappingsAt("TeamId", keywordMapping) 74 postMapping.AddFieldMappingsAt("ChannelId", keywordMapping) 75 postMapping.AddFieldMappingsAt("UserId", keywordMapping) 76 postMapping.AddFieldMappingsAt("CreateAt", dateMapping) 77 postMapping.AddFieldMappingsAt("Message", standardMapping) 78 postMapping.AddFieldMappingsAt("Type", keywordMapping) 79 postMapping.AddFieldMappingsAt("Hashtags", standardMapping) 80 postMapping.AddFieldMappingsAt("Attachments", standardMapping) 81 82 indexMapping := bleve.NewIndexMapping() 83 indexMapping.AddDocumentMapping("_default", postMapping) 84 85 return indexMapping 86 } 87 88 func getFileIndexMapping() *mapping.IndexMappingImpl { 89 fileMapping := bleve.NewDocumentMapping() 90 fileMapping.AddFieldMappingsAt("Id", keywordMapping) 91 fileMapping.AddFieldMappingsAt("CreatorId", keywordMapping) 92 fileMapping.AddFieldMappingsAt("ChannelId", keywordMapping) 93 fileMapping.AddFieldMappingsAt("CreateAt", dateMapping) 94 fileMapping.AddFieldMappingsAt("Name", standardMapping) 95 fileMapping.AddFieldMappingsAt("Content", standardMapping) 96 fileMapping.AddFieldMappingsAt("Extension", keywordMapping) 97 fileMapping.AddFieldMappingsAt("Content", standardMapping) 98 99 indexMapping := bleve.NewIndexMapping() 100 indexMapping.AddDocumentMapping("_default", fileMapping) 101 102 return indexMapping 103 } 104 105 func getUserIndexMapping() *mapping.IndexMappingImpl { 106 userMapping := bleve.NewDocumentMapping() 107 userMapping.AddFieldMappingsAt("Id", keywordMapping) 108 userMapping.AddFieldMappingsAt("SuggestionsWithFullname", keywordMapping) 109 userMapping.AddFieldMappingsAt("SuggestionsWithoutFullname", keywordMapping) 110 userMapping.AddFieldMappingsAt("TeamsIds", keywordMapping) 111 userMapping.AddFieldMappingsAt("ChannelsIds", keywordMapping) 112 113 indexMapping := bleve.NewIndexMapping() 114 indexMapping.AddDocumentMapping("_default", userMapping) 115 116 return indexMapping 117 } 118 119 func NewBleveEngine(cfg *model.Config, jobServer *jobs.JobServer) *BleveEngine { 120 return &BleveEngine{ 121 cfg: cfg, 122 jobServer: jobServer, 123 } 124 } 125 126 func (b *BleveEngine) getIndexDir(indexName string) string { 127 return filepath.Join(*b.cfg.BleveSettings.IndexDir, indexName+".bleve") 128 } 129 130 func (b *BleveEngine) createOrOpenIndex(indexName string, mapping *mapping.IndexMappingImpl) (bleve.Index, error) { 131 indexPath := b.getIndexDir(indexName) 132 if index, err := bleve.Open(indexPath); err == nil { 133 return index, nil 134 } 135 136 index, err := bleve.New(indexPath, mapping) 137 if err != nil { 138 return nil, err 139 } 140 return index, nil 141 } 142 143 func (b *BleveEngine) openIndexes() *model.AppError { 144 if atomic.LoadInt32(&b.ready) != 0 { 145 return model.NewAppError("Bleveengine.Start", "bleveengine.already_started.error", nil, "", http.StatusInternalServerError) 146 } 147 148 var err error 149 b.PostIndex, err = b.createOrOpenIndex(PostIndex, getPostIndexMapping()) 150 if err != nil { 151 return model.NewAppError("Bleveengine.Start", "bleveengine.create_post_index.error", nil, err.Error(), http.StatusInternalServerError) 152 } 153 154 b.FileIndex, err = b.createOrOpenIndex(FileIndex, getFileIndexMapping()) 155 if err != nil { 156 return model.NewAppError("Bleveengine.Start", "bleveengine.create_file_index.error", nil, err.Error(), http.StatusInternalServerError) 157 } 158 159 b.UserIndex, err = b.createOrOpenIndex(UserIndex, getUserIndexMapping()) 160 if err != nil { 161 return model.NewAppError("Bleveengine.Start", "bleveengine.create_user_index.error", nil, err.Error(), http.StatusInternalServerError) 162 } 163 164 b.ChannelIndex, err = b.createOrOpenIndex(ChannelIndex, getChannelIndexMapping()) 165 if err != nil { 166 return model.NewAppError("Bleveengine.Start", "bleveengine.create_channel_index.error", nil, err.Error(), http.StatusInternalServerError) 167 } 168 169 atomic.StoreInt32(&b.ready, 1) 170 return nil 171 } 172 173 func (b *BleveEngine) Start() *model.AppError { 174 if !*b.cfg.BleveSettings.EnableIndexing || *b.cfg.BleveSettings.IndexDir == "" { 175 return nil 176 } 177 178 b.Mutex.Lock() 179 defer b.Mutex.Unlock() 180 181 mlog.Info("EXPERIMENTAL: Starting Bleve") 182 183 return b.openIndexes() 184 } 185 186 func (b *BleveEngine) closeIndexes() *model.AppError { 187 if b.IsActive() { 188 if err := b.PostIndex.Close(); err != nil { 189 return model.NewAppError("Bleveengine.Stop", "bleveengine.stop_post_index.error", nil, err.Error(), http.StatusInternalServerError) 190 } 191 192 if err := b.FileIndex.Close(); err != nil { 193 return model.NewAppError("Bleveengine.Stop", "bleveengine.stop_file_index.error", nil, err.Error(), http.StatusInternalServerError) 194 } 195 196 if err := b.UserIndex.Close(); err != nil { 197 return model.NewAppError("Bleveengine.Stop", "bleveengine.stop_user_index.error", nil, err.Error(), http.StatusInternalServerError) 198 } 199 200 if err := b.ChannelIndex.Close(); err != nil { 201 return model.NewAppError("Bleveengine.Stop", "bleveengine.stop_channel_index.error", nil, err.Error(), http.StatusInternalServerError) 202 } 203 } 204 205 atomic.StoreInt32(&b.ready, 0) 206 return nil 207 } 208 209 func (b *BleveEngine) Stop() *model.AppError { 210 b.Mutex.Lock() 211 defer b.Mutex.Unlock() 212 213 mlog.Info("Stopping Bleve") 214 215 return b.closeIndexes() 216 } 217 218 func (b *BleveEngine) IsActive() bool { 219 return atomic.LoadInt32(&b.ready) == 1 220 } 221 222 func (b *BleveEngine) IsIndexingSync() bool { 223 return b.indexSync 224 } 225 226 func (b *BleveEngine) RefreshIndexes() *model.AppError { 227 return nil 228 } 229 230 func (b *BleveEngine) GetVersion() int { 231 return 0 232 } 233 234 func (b *BleveEngine) GetFullVersion() string { 235 return "0" 236 } 237 238 func (b *BleveEngine) GetPlugins() []string { 239 return []string{} 240 } 241 242 func (b *BleveEngine) GetName() string { 243 return EngineName 244 } 245 246 func (b *BleveEngine) TestConfig(cfg *model.Config) *model.AppError { 247 return nil 248 } 249 250 func (b *BleveEngine) deleteIndexes() *model.AppError { 251 if err := os.RemoveAll(b.getIndexDir(PostIndex)); err != nil { 252 return model.NewAppError("Bleveengine.PurgeIndexes", "bleveengine.purge_post_index.error", nil, err.Error(), http.StatusInternalServerError) 253 } 254 if err := os.RemoveAll(b.getIndexDir(UserIndex)); err != nil { 255 return model.NewAppError("Bleveengine.PurgeIndexes", "bleveengine.purge_user_index.error", nil, err.Error(), http.StatusInternalServerError) 256 } 257 if err := os.RemoveAll(b.getIndexDir(ChannelIndex)); err != nil { 258 return model.NewAppError("Bleveengine.PurgeIndexes", "bleveengine.purge_channel_index.error", nil, err.Error(), http.StatusInternalServerError) 259 } 260 return nil 261 } 262 263 func (b *BleveEngine) PurgeIndexes() *model.AppError { 264 if *b.cfg.BleveSettings.IndexDir == "" { 265 return nil 266 } 267 268 b.Mutex.Lock() 269 defer b.Mutex.Unlock() 270 271 mlog.Info("PurgeIndexes Bleve") 272 if err := b.closeIndexes(); err != nil { 273 return err 274 } 275 276 if err := b.deleteIndexes(); err != nil { 277 return err 278 } 279 280 return b.openIndexes() 281 } 282 283 func (b *BleveEngine) DataRetentionDeleteIndexes(cutoff time.Time) *model.AppError { 284 return nil 285 } 286 287 func (b *BleveEngine) IsAutocompletionEnabled() bool { 288 return *b.cfg.BleveSettings.EnableAutocomplete 289 } 290 291 func (b *BleveEngine) IsIndexingEnabled() bool { 292 return *b.cfg.BleveSettings.EnableIndexing 293 } 294 295 func (b *BleveEngine) IsSearchEnabled() bool { 296 return *b.cfg.BleveSettings.EnableSearching 297 } 298 299 func (b *BleveEngine) UpdateConfig(cfg *model.Config) { 300 b.Mutex.Lock() 301 defer b.Mutex.Unlock() 302 303 mlog.Info("UpdateConf Bleve") 304 305 if *cfg.BleveSettings.EnableIndexing != *b.cfg.BleveSettings.EnableIndexing || *cfg.BleveSettings.IndexDir != *b.cfg.BleveSettings.IndexDir { 306 if err := b.closeIndexes(); err != nil { 307 mlog.Error("Error closing Bleve indexes to update the config", mlog.Err(err)) 308 return 309 } 310 b.cfg = cfg 311 if err := b.openIndexes(); err != nil { 312 mlog.Error("Error opening Bleve indexes after updating the config", mlog.Err(err)) 313 } 314 return 315 } 316 b.cfg = cfg 317 }