Skip to content

Conversation

@wachterjohannes
Copy link
Contributor

Q A
Bug fix? no
New feature? yes
Docs? yes
Issues Fix #1562
License MIT

Description

This PR implements a query abstraction pattern for the Store component, enabling support for multiple query types (Vector, Text, Hybrid) with an integrated filter system. This addresses RFC #1562 and provides a flexible foundation for advanced retrieval use cases.

Summary of Changes

Query Abstraction

  • QueryInterface: Base interface for all query types with getType() and getFilter() methods
  • QueryType Enum: Defines Vector, Text, and Hybrid query types
  • Query Implementations:
    • VectorQuery: Classic vector similarity search (supported by all stores)
    • TextQuery: Full-text search or internal vectorization (ChromaDB, Postgres, Cache)
    • HybridQuery: Combined vector + text search with configurable semanticRatio parameter (Postgres, ChromaDB, Cache)

Filter System

  • FilterInterface: Base interface for query filters with getType() and toArray() methods
  • EqualFilter: Equality filter for metadata filtering (e.g., filtering by locale, category, status)
  • Filters are integrated directly into query objects

Store Updates

Postgres Store - Extended to support all three query types:

  • Vector search using pgvector extension
  • Full-text search using PostgreSQL's native FTS
  • Hybrid search with weighted scoring combining vector similarity and text relevance
  • EqualFilter support via JSONB operators

ChromaDB Store - Extended to support all three query types:

  • Vector and text queries via ChromaDB's native API
  • Hybrid query implementation with result merging
  • EqualFilter support via ChromaDB's filtering syntax

Pinecone, Redis, Qdrant Stores - Vector only with filter support:

  • Vector similarity search
  • EqualFilter support via respective backend filter syntaxes

Cache Store - All query types with filter support:

  • In-memory implementations for all query types
  • EqualFilter support via metadata filtering

API Changes

  • StoreInterface: Updated with new query(QueryInterface $query, array $options = []) signature
  • Capability Signaling: New supports(string $queryClass): bool method to check store capabilities
  • Retriever: Updated to use query abstraction with automatic capability detection
  • Exception: New UnsupportedQueryTypeException thrown for unsupported query types

Breaking Changes

Store::query() Signature Change

Before:

$store->query($vector, ['limit' => 10]);

After:

use Symfony\AI\Store\Query\VectorQuery;

$store->query(new VectorQuery($vector), ['limit' => 10]);

All existing code needs to wrap Vector objects in VectorQuery constructor.

Usage Examples

Vector Query with Filter

use Symfony\AI\Store\Query\VectorQuery;
use Symfony\AI\Store\Query\Filter\EqualFilter;

// Search for documents in English locale
$query = new VectorQuery($vector, new EqualFilter('locale', 'en'));
$results = $store->query($query, ['limit' => 10]);

Text Query

use Symfony\AI\Store\Query\TextQuery;

// Full-text search (Postgres, ChromaDB, Cache)
$query = new TextQuery('space adventure', new EqualFilter('category', 'scifi'));
$results = $store->query($query, ['limit' => 5]);

Hybrid Query

use Symfony\AI\Store\Query\HybridQuery;

// Combine vector and text with 70% vector weight
$query = new HybridQuery(
    $vector,
    'space adventure',
    0.7,  // semanticRatio (vector weight)
    new EqualFilter('status', 'published')
);
$results = $store->query($query);

Capability Checking

// Check store support before using query type
if ($store->supports(HybridQuery::class)) {
    $query = new HybridQuery($vector, $text);
} else {
    $query = new VectorQuery($vector);
}

@carsonbot carsonbot added Feature New feature Store Issues & PRs about the AI Store component Status: Needs Review labels Feb 8, 2026
@wachterjohannes wachterjohannes force-pushed the feature/query-abstraction-with-filters branch from cc6d736 to ccd1d40 Compare February 8, 2026 20:22
Implement query abstraction pattern to support multiple query types
(Vector, Text, Hybrid) with integrated filter system.

Key changes:
- Add QueryInterface with VectorQuery, TextQuery, and HybridQuery implementations
- Add FilterInterface with EqualFilter implementation
- Update StoreInterface with new query() signature and supports() method
- Implement filter support in all reference stores (Postgres, ChromaDB, Pinecone, Redis, Qdrant, Cache)
- Extend Postgres to support Vector, Text, and Hybrid queries with PostgreSQL FTS
- Update Retriever to use query abstraction with capability checking

Breaking change: Store::query() now accepts QueryInterface instead of Vector.
Migration: Wrap Vector in VectorQuery constructor.
@wachterjohannes wachterjohannes force-pushed the feature/query-abstraction-with-filters branch from ccd1d40 to ae3ba15 Compare February 8, 2026 20:23
$this->logger->debug('Document retrieval completed', ['retrieved_count' => $count]);
}

private function createQuery(string $query, array $options): QueryInterface
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the most important part of this PR - it selects the right type of query

{
public function getType(): QueryType;

public function getFilter(): ?FilterInterface;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure how the filter should look like and how we could validate them in the store. @chr-hertel for equal its easy but for more complex filters it could be hard to implement that in the stores

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's go incremental and skip the filter part for the first PR - we can slice that, right?

@wachterjohannes
Copy link
Contributor Author

for all who take a look at this PR this is a POC as a discussion base

Copy link
Member

@chr-hertel chr-hertel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @wachterjohannes for jumping on that - much appreciated 🙏

I left some comments to also slim down the diff here a bit.

Comment on lines +44 to +47
public function getType(): QueryType
{
return QueryType::Text;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we only use that at exceptions right now? let's drop it then or do i miss something?

if ($this->store->supports(HybridQuery::class)) {
$this->logger->debug('Store supports hybrid queries, using HybridQuery with semantic ratio', ['semanticRatio' => $options['semanticRatio'] ?? 0.5]);

return new HybridQuery($this->vectorizer->vectorize($query), $query, $options['semanticRatio'] ?? 0.5);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the assumption fair to use $query for both parts?

*
* @author Johannes Wachter <johannes@sulu.io>
*/
enum QueryType: string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure we need that, do we?

{
public function getType(): QueryType;

public function getFilter(): ?FilterInterface;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's go incremental and skip the filter part for the first PR - we can slice that, right?

private readonly ?FilterInterface $filter = null,
) {
if ($semanticRatio < 0.0 || $semanticRatio > 1.0) {
throw new \InvalidArgumentException(\sprintf('Semantic ratio must be between 0.0 and 1.0, got %.2f', $semanticRatio));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use Symfony\AI\Store\Exception\InvalidArgumentException instead of native one

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature New feature Status: Needs Work Store Issues & PRs about the AI Store component

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Store] Open Store::query(Vector) method for different query types

3 participants