@@ -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