-
Notifications
You must be signed in to change notification settings - Fork 4.4k
.Net: docs: Add ADR-0065 for LINQ-based ITextSearch filtering migration strategy #13335
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feature-text-search-linq
Are you sure you want to change the base?
.Net: docs: Add ADR-0065 for LINQ-based ITextSearch filtering migration strategy #13335
Conversation
Add comprehensive Architectural Decision Record documenting the dual interface pattern approach for migrating ITextSearch from clause-based filtering to LINQ expressions. Documents migration strategy, obsolete marking, and future removal path.
- Add 'Text Search Contains() Support Implementation' subsection - Documents query enhancement pattern for Brave/Tavily - Explains SearchQueryFilterClause design decision - Lists alternatives and consequences - Add 'SearchQueryFilterClause Public Visibility' subsection - Documents public API decision and rationale - Explains FilterClause internal constructor constraint - Lists alternatives considered (move to Plugins.Web, InternalsVisibleTo, etc.) These implementation decisions are integral to the overall LINQ-based text search filtering architecture and belong within the main ADR. microsoft#10456
|
|
||
| **Alternatives Considered**: | ||
|
|
||
| 1. **Move to Plugins.Web**: Impossible due to internal constructor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update per latest discussion, and changes:
…terClause decision in ADR-0065 Documents the architectural role of FilterClause as the common translation layer and updates the SearchQueryFilterClause visibility decision to reflect the implemented approach. Changes: - Added FilterClause architecture section with diagrams showing dual path convergence - Updated SearchQueryFilterClause decision: Made FilterClause constructor public and moved SearchQueryFilterClause to Plugins.Web (internal) - Clarified SearchQueryFilterClause is LINQ-only (never created by users) - Documented trade-off: Opening FilterClause to external inheritance to minimize MEVD API surface - Explained why FilterClause stays after legacy removal (LINQ translator needs it) - Distinguished user-facing APIs (removed in Phase 3) from internal translation layer (stays) - Added cross-reference between architecture explanation and decision rationale sections This captures the architectural discussion and final decision from PR microsoft#13191 review with @westey-m.
Changed FilterClause constructor from public to protected, which is the proper approach for abstract base classes. Changes: - Updated 'SearchQueryFilterClause Placement Decision' section (renamed from 'Public Visibility') - Simplified rationale: protected constructor allows inheritance while preventing instantiation - Removed mention of CA1012 suppression (no longer needed with protected) - Removed 'trade-off' language since protected is the standard practice - Updated cross-reference note to use new section name This reflects the final implementation using protected constructor as suggested in PR review.
|
|
||
| ## Context and Problem Statement | ||
|
|
||
| The ITextSearch interface uses a clause-based TextSearchFilter approach for expressing filter predicates. This design creates runtime errors from property name typos, lacks type safety, and requires conversion to obsolete VectorSearchFilter APIs internally. The interface needs modernization to provide compile-time safety, IntelliSense support, and alignment with Microsoft.Extensions.VectorData LINQ-based filtering patterns. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clarify the TextSearchFilter usage in the filters versus in internal representation uses. The former will be obsolete, the later will be retained internally to reuse Web Plugins translation code
| **Why FilterClause Stays After Legacy Removal**: | ||
|
|
||
| Even when we remove the legacy `ITextSearch` interface and `TextSearchFilter` builder API in Phase 3, `FilterClause` types remain because: | ||
|
|
||
| 1. **Modern LINQ path still needs them**: The LINQ translator converts expressions to `FilterClause` instances | ||
| 2. **Web connectors process them**: All web connectors translate `FilterClause` to API-specific parameters | ||
| 3. **Not part of public API**: Users never see `FilterClause` types - they're internal translation layer | ||
| 4. **Vector stores bypass them**: Modern vector stores use LINQ expressions directly via `VectorSearchOptions<TRecord>.Filter` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clarify the removal from the VectorSearch and Public API
| ### Pattern Comparison | ||
|
|
||
| ``` | ||
| ┌───────────────────────────────────────────────────────────────────────┐ | ||
| │ Pattern A vs Pattern B │ | ||
| ├───────────────────────────────────────────────────────────────────────┤ | ||
| │ │ | ||
| │ Pattern A: Direct LINQ Passthrough │ | ||
| │ Used by: VectorStoreTextSearch │ | ||
| │ ┌──────────────────────────────────────────────────────────────┐ │ | ||
| │ │ │ │ | ||
| │ │ Legacy: TextSearchFilter → VectorSearchFilter.OldFilter │ │ | ||
| │ │ (pragma warnings, temporary during transition) │ │ | ||
| │ │ │ │ | ||
| │ │ Modern: LINQ Expression → VectorSearchOptions.Filter │ │ | ||
| │ │ (direct passthrough, no conversion) │ │ | ||
| │ │ │ │ | ||
| │ │ Result: Two independent paths, zero overhead │ │ | ||
| │ │ │ │ | ||
| │ └──────────────────────────────────────────────────────────────┘ │ | ||
| │ │ | ||
| │ Pattern B: LINQ-to-Legacy Conversion │ | ||
| │ Used by: BingTextSearch, GoogleTextSearch, Tavily, Brave │ | ||
| │ ┌──────────────────────────────────────────────────────────────┐ │ | ||
| │ │ │ │ | ||
| │ │ Legacy: TextSearchFilter → API parameters │ │ | ||
| │ │ (existing implementation, unchanged) │ │ | ||
| │ │ │ │ | ||
| │ │ Modern: LINQ Expression → [Analyze] → TextSearchFilter │ │ | ||
| │ │ → Delegate to legacy path │ │ | ||
| │ │ │ │ | ||
| │ │ Result: Suitable for network-bound operations │ │ | ||
| │ │ │ │ | ||
| │ └──────────────────────────────────────────────────────────────┘ │ | ||
| │ │ | ||
| └───────────────────────────────────────────────────────────────────────┘ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review content organization for a smoother flow.
Add ADR-0065: LINQ-Based Filtering for ITextSearch Interface
Summary
This PR adds a comprehensive Architectural Decision Record (ADR) documenting the decision to migrate
ITextSearchfrom clause-based filtering to LINQ-based filtering using a dual interface pattern.Context
Issue: #10456
The existing
ITextSearchinterface usesTextSearchFilter(clause-based approach) which:VectorSearchFilterAPIs internallyDecision
Chosen Approach: Dual Interface Pattern (Option 3)
ITextSearch<TRecord>with LINQ filtering (Expression<Func<TRecord, bool>>)ITextSearchmarked[Obsolete]for backward compatibilityKey Architectural Points
Migration Strategy (Temporary by Design)
Why Mark as
[Obsolete]NowImplementation Patterns Documented
Pattern A: Direct LINQ Passthrough (VectorStoreTextSearch)
Pattern B: LINQ-to-Legacy Conversion (Bing, Google, Tavily, Brave)
Benefits
✅ Zero breaking changes - existing code continues working
✅ Type safety - compile-time validation and IntelliSense
✅ AOT compatible - no
[RequiresDynamicCode]attributes✅ Clear migration path - deprecation warnings guide users
✅ Future-ready - establishes path for technical debt removal
Related PRs
This ADR documents the architectural decision behind:
Review Notes
Per ADR process requirements:
accepted(implementation already complete)This ADR serves as:
Checklist
accepted0065-linq-based-text-search-filtering.mddotnet/docs/decisions/Target Branch
feature-text-search-linq