mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-05-20 01:36:37 +00:00
fix(issue-search): single exclude query was erroneosly considered as must (#12589)
The bleve indexer included a fast path to consider a single token to be of MUST rather than should. However, the condition missed an additional check and would erroneosly include a NOT as a MUST. This was not spotted by the tests as such exclude queries were usually made along with another term to avoid noise. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/12589 Reviewed-by: Gusted <gusted@noreply.codeberg.org>
This commit is contained in:
parent
cf3b4a160d
commit
17f5ce6ce3
2 changed files with 49 additions and 19 deletions
|
|
@ -151,28 +151,33 @@ func (b *Indexer) Delete(_ context.Context, ids ...int64) error {
|
|||
return batch.Flush()
|
||||
}
|
||||
|
||||
// Search searches for issues by given conditions.
|
||||
// Returns the matching issue IDs
|
||||
func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (*internal.SearchResult, error) {
|
||||
func termQuery(token internal.Token) query.Query {
|
||||
innerQ := bleve.NewDisjunctionQuery(
|
||||
inner_bleve.MatchPhraseQuery(token.Term, "title", issueIndexerAnalyzer, token.Fuzzy, 2.0),
|
||||
inner_bleve.MatchPhraseQuery(token.Term, "content", issueIndexerAnalyzer, token.Fuzzy, 1.0),
|
||||
inner_bleve.MatchPhraseQuery(token.Term, "comments", issueIndexerAnalyzer, token.Fuzzy, 1.0))
|
||||
|
||||
if issueID, err := token.ParseIssueReference(); err == nil {
|
||||
idQuery := inner_bleve.NumericEqualityQuery(issueID, "index")
|
||||
idQuery.SetBoost(20.0)
|
||||
innerQ.AddQuery(idQuery)
|
||||
}
|
||||
return innerQ
|
||||
}
|
||||
|
||||
// Create a boolean query with the provided tokens (if any)
|
||||
func keywordQuery(tokens []internal.Token) *query.BooleanQuery {
|
||||
q := bleve.NewBooleanQuery()
|
||||
|
||||
for _, token := range options.Tokens {
|
||||
innerQ := bleve.NewDisjunctionQuery(
|
||||
inner_bleve.MatchPhraseQuery(token.Term, "title", issueIndexerAnalyzer, token.Fuzzy, 2.0),
|
||||
inner_bleve.MatchPhraseQuery(token.Term, "content", issueIndexerAnalyzer, token.Fuzzy, 1.0),
|
||||
inner_bleve.MatchPhraseQuery(token.Term, "comments", issueIndexerAnalyzer, token.Fuzzy, 1.0))
|
||||
|
||||
if issueID, err := token.ParseIssueReference(); err == nil {
|
||||
idQuery := inner_bleve.NumericEqualityQuery(issueID, "index")
|
||||
idQuery.SetBoost(20.0)
|
||||
innerQ.AddQuery(idQuery)
|
||||
}
|
||||
|
||||
if len(options.Tokens) == 1 {
|
||||
q.AddMust(innerQ)
|
||||
break
|
||||
}
|
||||
// If there is only a single term the user is likely looking for
|
||||
// a MUST rather than a SHOULD
|
||||
if len(tokens) == 1 && tokens[0].Kind != internal.BoolOptNot {
|
||||
q.AddMust(termQuery(tokens[0]))
|
||||
return q
|
||||
}
|
||||
|
||||
for _, token := range tokens {
|
||||
innerQ := termQuery(token)
|
||||
switch token.Kind {
|
||||
case internal.BoolOptMust:
|
||||
q.AddMust(innerQ)
|
||||
|
|
@ -183,6 +188,14 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
|
|||
}
|
||||
}
|
||||
|
||||
return q
|
||||
}
|
||||
|
||||
// Search searches for issues by given conditions.
|
||||
// Returns the matching issue IDs
|
||||
func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (*internal.SearchResult, error) {
|
||||
q := keywordQuery(options.Tokens)
|
||||
|
||||
var filters []query.Query
|
||||
if len(options.RepoIDs) > 0 || options.AllPublic {
|
||||
var repoQueries []query.Query
|
||||
|
|
|
|||
|
|
@ -171,6 +171,23 @@ var cases = []*testIndexerCase{
|
|||
ExpectedIDs: []int64{1002},
|
||||
ExpectedTotal: 1,
|
||||
},
|
||||
{
|
||||
Name: "Keyword Exclude Only",
|
||||
ExtraData: []*internal.IndexerData{
|
||||
{ID: 1000, Title: "hello"},
|
||||
{ID: 1001, Content: "hello world"},
|
||||
{ID: 1002, Comments: []string{"hi", "hello world"}},
|
||||
},
|
||||
Keyword: "-hello",
|
||||
SearchOptions: &internal.SearchOptions{
|
||||
SortBy: internal.SortByCreatedDesc,
|
||||
},
|
||||
Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
|
||||
for _, hit := range result.Hits {
|
||||
assert.NotContains(t, []int64{1000, 1001, 1002}, hit.ID)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Keyword Fuzzy",
|
||||
ExtraData: []*internal.IndexerData{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue