From 0db5e3922fd5045b3f7f518ad65e42138f0325c4 Mon Sep 17 00:00:00 2001 From: George Goldberg Date: Thu, 18 May 2017 16:26:52 +0100 Subject: PLT-6472: Basic Elastic Search implementation. (#6382) * PLT-6472: Basic Elastic Search implementation. This currently supports indexing of posts at create/update/delete time. It does not support batch indexing or reindexing, and does not support any entities other than posts yet. The purpose is to more-or-less replicate the existing full-text search feature but with some of the immediate benefits of using elastic search. * Alter settings for AWS compatability. * Remove unneeded i18n strings. --- app/post.go | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 15 deletions(-) (limited to 'app/post.go') diff --git a/app/post.go b/app/post.go index bf61bafb2..341287cf4 100644 --- a/app/post.go +++ b/app/post.go @@ -125,6 +125,11 @@ func CreatePost(post *model.Post, teamId string, triggerWebhooks bool) (*model.P rpost = result.Data.(*model.Post) } + esInterface := einterfaces.GetElasticSearchInterface() + if (esInterface != nil && *utils.Cfg.ElasticSearchSettings.EnableIndexing) { + go esInterface.IndexPost(rpost, teamId) + } + if einterfaces.GetMetricsInterface() != nil { einterfaces.GetMetricsInterface().IncrementPostCreate() } @@ -308,6 +313,17 @@ func UpdatePost(post *model.Post, safeUpdate bool) (*model.Post, *model.AppError } else { rpost := result.Data.(*model.Post) + esInterface := einterfaces.GetElasticSearchInterface() + if (esInterface != nil && *utils.Cfg.ElasticSearchSettings.EnableIndexing) { + go func() { + if rchannel := <-Srv.Store.Channel().GetForPost(rpost.Id); rchannel.Err != nil { + l4g.Error("Couldn't get channel %v for post %v for ElasticSearch indexing.", rpost.ChannelId, rpost.Id) + } else { + esInterface.IndexPost(rpost, rchannel.Data.(*model.Channel).TeamId) + } + }() + } + sendUpdatedPostEvent(rpost) InvalidateCacheForChannelPosts(rpost.ChannelId) @@ -484,6 +500,11 @@ func DeletePost(postId string) (*model.Post, *model.AppError) { go DeletePostFiles(post) go DeleteFlaggedPosts(post.Id) + esInterface := einterfaces.GetElasticSearchInterface() + if (esInterface != nil && *utils.Cfg.ElasticSearchSettings.EnableIndexing) { + go esInterface.DeletePost(post.Id) + } + InvalidateCacheForChannelPosts(post.ChannelId) return post, nil @@ -509,27 +530,84 @@ func DeletePostFiles(post *model.Post) { func SearchPostsInTeam(terms string, userId string, teamId string, isOrSearch bool) (*model.PostList, *model.AppError) { paramsList := model.ParseSearchParams(terms) - channels := []store.StoreChannel{} - for _, params := range paramsList { - params.OrTerms = isOrSearch - // don't allow users to search for everything - if params.Terms != "*" { - channels = append(channels, Srv.Store.Post().Search(teamId, userId, params)) + esInterface := einterfaces.GetElasticSearchInterface() + if (esInterface != nil && *utils.Cfg.ElasticSearchSettings.EnableSearching && utils.IsLicensed && *utils.License.Features.ElasticSearch) { + finalParamsList := []*model.SearchParams{} + + for _, params := range paramsList { + params.OrTerms = isOrSearch + // Don't allow users to search for "*" + if params.Terms != "*" { + // Convert channel names to channel IDs + for idx, channelName := range params.InChannels { + if channel, err := GetChannelByName(channelName, teamId); err != nil { + l4g.Error(err) + } else { + params.InChannels[idx] = channel.Id + } + } + + // Convert usernames to user IDs + for idx, username := range params.FromUsers { + if user, err := GetUserByUsername(username); err != nil { + l4g.Error(err) + } else { + params.FromUsers[idx] = user.Id + } + } + + finalParamsList = append(finalParamsList, params) + } } - } - posts := model.NewPostList() - for _, channel := range channels { - if result := <-channel; result.Err != nil { - return nil, result.Err + // We only allow the user to search in channels they are a member of. + userChannels, err := GetChannelsForUser(teamId, userId) + if err != nil { + l4g.Error(err) + return nil, err + } + + postIds, err := einterfaces.GetElasticSearchInterface().SearchPosts(userChannels, finalParamsList) + if err != nil { + return nil, err + } + + // Get the posts + postList := model.NewPostList() + if presult := <-Srv.Store.Post().GetPostsByIds(postIds); presult.Err != nil { + return nil, presult.Err } else { - data := result.Data.(*model.PostList) - posts.Extend(data) + for _, p := range presult.Data.([]*model.Post) { + postList.AddPost(p) + postList.AddOrder(p.Id) + } } - } - return posts, nil + return postList, nil + } else { + channels := []store.StoreChannel{} + + for _, params := range paramsList { + params.OrTerms = isOrSearch + // don't allow users to search for everything + if params.Terms != "*" { + channels = append(channels, Srv.Store.Post().Search(teamId, userId, params)) + } + } + + posts := model.NewPostList() + for _, channel := range channels { + if result := <-channel; result.Err != nil { + return nil, result.Err + } else { + data := result.Data.(*model.PostList) + posts.Extend(data) + } + } + + return posts, nil + } } func GetFileInfosForPost(postId string, readFromMaster bool) ([]*model.FileInfo, *model.AppError) { -- cgit v1.2.3-1-g7c22