Search by

inm39 / mariadb-vector-bundle

INM39

Symfony bundle providing Doctrine DBAL type and DQL functions for MariaDB Vector (VECTOR type, VEC_DISTANCE_*, semantic search). Requires MariaDB >= 11.7.

Package info

github.com/IMAMx39/mariadb-vector-bundle

Type:symfony-bundle

pkg:composer/inm39/mariadb-vector-bundle

Statistics

Installs: 4

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.1 2026-07-24 09:58 UTC

This package is auto-updated.

Last update: 2026-08-24 10:38:58 UTC


README

Symfony bundle for MariaDB Vector (MariaDB ≥ 11.7 / 11.8 LTS): Doctrine vector DBAL type, VEC_* DQL functions and a repository trait for semantic / nearest-neighbour search.

Bring RAG and semantic search to your existing MariaDB — no extra vector database needed.

Features

  • vector Doctrine DBAL type — map VECTOR(N) columns to plain PHP float[]
  • ✅ DQL functions: VEC_DISTANCE, VEC_DISTANCE_COSINE, VEC_DISTANCE_EUCLIDEAN, VEC_FROMTEXT, VEC_TOTEXT
  • VectorSearchTrait for repositories: findNearest() in one line
  • ✅ Zero configuration — the bundle prepends everything into DoctrineBundle

Requirements

  • PHP ≥ 8.1
  • Symfony 6.4 / 7.x
  • doctrine/orm ≥ 2.16 or 3.x
  • MariaDB ≥ 11.7 (11.8 LTS recommended)

Installation

composer require inm39/mariadb-vector-bundle

This bundle has no Symfony Flex recipe, so you need to register it by hand:

// config/bundles.php
return [
    // ...
    INM39\MariadbVectorBundle\MariadbVectorBundle::class => ['all' => true],
];

No config/packages/mariadb_vector.yaml is needed — see Configuration below, it's only required if you want to override the default.

Usage

1. Entity

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: DocumentRepository::class)]
class Document
{
    #[ORM\Id, ORM\GeneratedValue, ORM\Column]
    private ?int $id = null;

    #[ORM\Column(type: 'text')]
    private string $content;

    /** @var list<float> — `length` is the vector dimension */
    #[ORM\Column(type: 'vector', length: 768)]
    private array $embedding = [];

    // getters/setters...
}

2. Migration — add the VECTOR INDEX manually

The schema tool generates the VECTOR(768) column, but the vector index must be added by hand (one per table, column must be NOT NULL):

public function up(Schema $schema): void
{
    $this->addSql('ALTER TABLE document ADD VECTOR INDEX (embedding) DISTANCE=cosine M=8');
}

3. Repository search

use INM39\MariadbVectorBundle\Repository\VectorSearchTrait;

class DocumentRepository extends ServiceEntityRepository
{
    use VectorSearchTrait;
}
// $queryVector: float[] from your embedding model (Ollama, TEI, OpenAI...)
$results = $documentRepository->findNearest('embedding', $queryVector, limit: 5);

// With distances:
foreach ($documentRepository->findNearestWithDistance('embedding', $queryVector) as $row) {
    $document = $row[0];
    $distance = $row['distance'];
}

4. Or raw DQL

$documents = $em->createQuery(
    'SELECT d, VEC_DISTANCE_COSINE(d.embedding, VEC_FROMTEXT(:vec)) AS HIDDEN dist
     FROM App\Entity\Document d
     ORDER BY dist ASC'
)
->setParameter('vec', json_encode($queryVector))
->setMaxResults(10)
->getResult();

⚠️ Performance notes (index usage)

MariaDB uses the vector index only when the query is:

ORDER BY VEC_DISTANCE_*(column, vector) ASC LIMIT n

on the bare distance call (or its alias). These patterns fall back to a full table scan:

  • Wrapping the distance in an expression (1 - VEC_DISTANCE_COSINE(...)) → compute the similarity score in an outer query instead.
  • WHERE VEC_DISTANCE(...) < threshold without ORDER BY ... LIMIT.
  • Using a distance function that doesn't match the index metric (DISTANCE=cosine vs euclidean).

Configuration

Default config (nothing to do):

# config/packages/mariadb_vector.yaml
mariadb_vector:
    register_dql_functions: true

Set register_dql_functions: false if you use multiple entity managers and prefer registering the DQL functions yourself per-manager.

Generating embeddings

This bundle does not generate embeddings — pair it with any model. Example with Ollama (nomic-embed-text:v1.5):

$response = $httpClient->request('POST', 'http://localhost:11434/api/embeddings', [
    'json' => [
        'model' => 'nomic-embed-text:v1.5',
        'prompt' => 'search_document: ' . $content,
    ],
]);
$embedding = $response->toArray()['embedding']; // float[768]

Running tests

composer install
vendor/bin/phpunit

License

MIT