Skip to content

Commit c9472fb

Browse files
authored
Use boolean query DSL (#1851)
1 parent 96aeda1 commit c9472fb

File tree

1 file changed

+20
-77
lines changed

1 file changed

+20
-77
lines changed

src/api/Elastic.Documentation.Api.Infrastructure/Adapters/Search/ElasticsearchGateway.cs

Lines changed: 20 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,24 @@ public ElasticsearchGateway(ElasticsearchOptions elasticsearchOptions, ILogger<E
7575

7676
var searchQuery = query.Replace("dotnet", "net", StringComparison.InvariantCultureIgnoreCase);
7777

78+
var lexicalSearchRetriever =
79+
((Query)new PrefixQuery(Infer.Field<DocumentDto>(f => f.Title.Suffix("keyword")), searchQuery) { Boost = 10.0f, CaseInsensitive = true }
80+
|| new MatchQuery(Infer.Field<DocumentDto>(f => f.Title), searchQuery) { Operator = Operator.And, Boost = 8.0f }
81+
|| new MatchBoolPrefixQuery(Infer.Field<DocumentDto>(f => f.Title), searchQuery) { Boost = 6.0f }
82+
|| new MatchQuery(Infer.Field<DocumentDto>(f => f.Abstract), searchQuery) { Boost = 4.0f }
83+
|| new MatchQuery(Infer.Field<DocumentDto>(f => f.Parents.First().Title), searchQuery) { Boost = 2.0f }
84+
|| new MatchQuery(Infer.Field<DocumentDto>(f => f.Title), searchQuery) { Fuzziness = 1, Boost = 1.0f }
85+
)
86+
&& !(Query)new TermsQuery(Infer.Field<DocumentDto>(f => f.Url.Suffix("keyword")), new TermsQueryField(["/docs", "/docs/", "/docs/404", "/docs/404/"]))
87+
;
88+
var semanticSearchRetriever =
89+
((Query)new SemanticQuery("title.semantic_text", searchQuery) { Boost = 5.0f }
90+
|| new SemanticQuery("abstract", searchQuery) { Boost = 3.0f }
91+
)
92+
&& !(Query)new TermsQuery(Infer.Field<DocumentDto>(f => f.Url.Suffix("keyword")),
93+
new TermsQueryField(["/docs", "/docs/", "/docs/404", "/docs/404/"]))
94+
;
95+
7896
try
7997
{
8098
var response = await _client.SearchAsync<DocumentDto>(s => s
@@ -83,84 +101,9 @@ public ElasticsearchGateway(ElasticsearchOptions elasticsearchOptions, ILogger<E
83101
.Rrf(rrf => rrf
84102
.Retrievers(
85103
// Lexical/Traditional search retriever
86-
ret => ret.Standard(std => std
87-
.Query(q => q
88-
.Bool(b => b
89-
.Should(
90-
// Tier 1: Exact/Prefix matches (highest priority)
91-
sh => sh.Prefix(p => p
92-
.Field("title.keyword")
93-
.Value(searchQuery)
94-
.CaseInsensitive(true)
95-
.Boost(10.0f) // Highest importance - exact prefix matches
96-
),
97-
// Tier 2: Title matching with AND operator
98-
sh => sh.Match(m => m
99-
.Field(f => f.Title)
100-
.Query(searchQuery)
101-
.Operator(Operator.And)
102-
.Boost(8.0f) // High importance - all terms must match
103-
),
104-
// Tier 3: Match bool prefix for partial matches
105-
sh => sh.MatchBoolPrefix(m => m
106-
.Field(f => f.Title)
107-
.Query(searchQuery)
108-
.Boost(6.0f) // Medium-high importance - partial matches
109-
),
110-
// Tier 4: Abstract matching
111-
sh => sh.Match(m => m
112-
.Field(f => f.Abstract)
113-
.Query(searchQuery)
114-
.Boost(4.0f) // Medium importance - content matching
115-
),
116-
// Tier 5: Parent matching
117-
sh => sh.Match(m => m
118-
.Field("parents.title")
119-
.Query(searchQuery)
120-
.Boost(2.0f) // Lower importance - parent context
121-
),
122-
// Tier 6: Fuzzy fallback
123-
sh => sh.Match(m => m
124-
.Field(f => f.Title)
125-
.Query(searchQuery)
126-
.Fuzziness(1)
127-
.Boost(1.0f) // Lowest importance - fuzzy fallback
128-
)
129-
)
130-
.MustNot(mn => mn.Terms(t => t
131-
.Field("url.keyword")
132-
.Terms(factory => factory.Value("/docs", "/docs/", "/docs/404", "/docs/404/"))
133-
))
134-
.MinimumShouldMatch(1)
135-
)
136-
)
137-
),
104+
ret => ret.Standard(std => std.Query(lexicalSearchRetriever)),
138105
// Semantic search retriever
139-
ret => ret.Standard(std => std
140-
.Query(q => q
141-
.Bool(b => b
142-
.Should(
143-
// Title semantic search
144-
sh => sh.Semantic(sem => sem
145-
.Field("title.semantic_text")
146-
.Query(searchQuery)
147-
.Boost(5.0f) // Higher importance - title semantic matching
148-
),
149-
// Abstract semantic search
150-
sh => sh.Semantic(sem => sem
151-
.Field("abstract")
152-
.Query(searchQuery)
153-
.Boost(3.0f) // Medium importance - content semantic matching
154-
)
155-
)
156-
.MustNot(mn => mn.Terms(t => t
157-
.Field("url.keyword")
158-
.Terms(factory => factory.Value("/docs", "/docs/", "/docs/404", "/docs/404/"))
159-
))
160-
.MinimumShouldMatch(1)
161-
)
162-
)
163-
)
106+
ret => ret.Standard(std => std.Query(semanticSearchRetriever))
164107
)
165108
.RankConstant(60) // Controls how much weight is given to document ranking
166109
)

0 commit comments

Comments
 (0)