Avoid simple config when doing FTS in Postgres (#35063) (#35179)
Some checks failed
ESR Upgrade / Run ESR upgrade script from 5.37 to 7.8 (push) Has been cancelled
ESR Upgrade / Run ESR upgrade script from 5.37 to 6.3 (push) Has been cancelled
ESR Upgrade / Run ESR upgrade script from 6.3 to 7.8 (push) Has been cancelled
Server CI Master / master-ci (push) Has been cancelled
Web App CI Master / master-ci (push) Has been cancelled

This commit reverts PR #30214, which addressed bug MM-60790 but caused a
performance regression tracked by MM-66782.

This revert has two implications:

1. The performance issue is solved.
2. The original bug is re-introduced.

Re-introducing the original bug seems not to be ideal, but I argue that
the original PR did not actually fix the bug:

- Before that PR, looking for a quoted string would return additional
  results: the UX was slightly confusing, because when the user looked
  for the word "stateful", the results would contain matches like
  "states" (see MM-60790).
- After that PR, looking for a quoted string can timeout, so that the
  list of results becomes empty. The UX here may be less confusing,
  since the user simply doesn't find what they're looking for, and they
  may assume that string is not present in any post, but it's completely
  wrong: the result list is empty because the SQL query timed out and
  thus the endpoint returned 0 results.

The solution to the original issue should be addressed via
Elasticsearch, which should provide a more refined and precise search
results.

For more information on the investigation on this issue and the
motivation behind the revert, see
https://mattermost.atlassian.net/wiki/x/IYAk_w

Co-authored-by: Mattermost Build <build@mattermost.com>
This commit is contained in:
Alejandro García Montoro 2026-02-04 13:00:44 +01:00 committed by GitHub
parent 463f7a0511
commit fddd4a70bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 0 additions and 74 deletions

View file

@ -35,11 +35,6 @@ var searchPostStoreTests = []searchTest{
Fn: testSearchANDORQuotesCombinations,
Tags: []string{EnginePostgres, EngineMySQL, EngineElasticSearch},
},
{
Name: "Should be able to search without stemming",
Fn: testStemming,
Tags: []string{EnginePostgres, EngineMySQL},
},
{
// Postgres supports search with and without quotes
Name: "Should be able to search for email addresses with or without quotes",
@ -472,65 +467,6 @@ func testSearchANDORQuotesCombinations(t *testing.T, th *SearchTestHelper) {
}
}
func testStemming(t *testing.T, th *SearchTestHelper) {
p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "great minds think", "", model.PostTypeDefault, 0, false)
require.NoError(t, err)
p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "mindful of what you think", "", model.PostTypeDefault, 0, false)
require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id)
testCases := []struct {
name string
terms string
orTerms bool
expectedLen int
expectedIDs []string
}{
{
name: "simple search, no stemming",
terms: `"minds think"`,
orTerms: false,
expectedLen: 1,
expectedIDs: []string{p1.Id},
},
{
name: "simple search, single word, no stemming",
terms: `"minds"`,
orTerms: false,
expectedLen: 1,
expectedIDs: []string{p1.Id},
},
{
name: "non-simple search, stemming",
terms: `minds think`,
orTerms: true,
expectedLen: 2,
expectedIDs: []string{p1.Id, p2.Id},
},
{
name: "simple search, no stemming, no results",
terms: `"mind"`,
orTerms: false,
expectedLen: 0,
expectedIDs: []string{},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
params := &model.SearchParams{Terms: tc.terms, OrTerms: tc.orTerms}
results, err := th.Store.Post().SearchPostsForUser(th.Context, []*model.SearchParams{params}, th.User.Id, th.Team.Id, 0, 20)
require.NoError(t, err)
require.Len(t, results.Posts, tc.expectedLen)
for _, id := range tc.expectedIDs {
th.checkPostInSearchResults(t, id, results.Posts)
}
})
}
}
func testSearchEmailAddresses(t *testing.T, th *SearchTestHelper) {
p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "email test@test.com", "", model.PostTypeDefault, 0, false)
require.NoError(t, err)

View file

@ -2160,7 +2160,6 @@ func (s *SqlPostStore) search(teamId string, userId string, params *model.Search
terms = wildCardRegex.ReplaceAllLiteralString(terms, ":* ")
excludedTerms = wildCardRegex.ReplaceAllLiteralString(excludedTerms, ":* ")
simpleSearch := false
// Replace spaces with to_tsquery symbols
replaceSpaces := func(input string, excludedInput bool) string {
if input == "" {
@ -2172,11 +2171,6 @@ func (s *SqlPostStore) search(teamId string, userId string, params *model.Search
// Replace spaces within quoted strings with '<->'
input = quotedStringsRegex.ReplaceAllStringFunc(input, func(match string) string {
// If the whole search term is a quoted string,
// we don't want to do stemming.
if input == match {
simpleSearch = true
}
return strings.Replace(match, " ", "<->", -1)
})
@ -2197,10 +2191,6 @@ func (s *SqlPostStore) search(teamId string, userId string, params *model.Search
}
textSearchCfg := s.pgDefaultTextSearchConfig
if simpleSearch {
textSearchCfg = "simple"
}
searchClause := fmt.Sprintf("to_tsvector('%[1]s', %[2]s) @@ to_tsquery('%[1]s', ?)", textSearchCfg, searchType)
baseQuery = baseQuery.Where(searchClause, tsQueryClause)
} else if s.DriverName() == model.DatabaseDriverMysql {