Skip to content

Add MariaDB Vector DocumentStore integration - #3565

Open
SyedShahmeerAli12 wants to merge 24 commits into
deepset-ai:mainfrom
SyedShahmeerAli12:feat/mariadb-document-store-2340
Open

Add MariaDB Vector DocumentStore integration#3565
SyedShahmeerAli12 wants to merge 24 commits into
deepset-ai:mainfrom
SyedShahmeerAli12:feat/mariadb-document-store-2340

Conversation

@SyedShahmeerAli12

@SyedShahmeerAli12 SyedShahmeerAli12 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Part of #2340

Implements a complete MariaDB document store integration using MariaDB 11.7+ native VECTOR support.

  • MariaDBDocumentStore full DocumentStore protocol (write_documents, filter_documents, delete_documents, count_documents)
  • Vector similarity search using VEC_DISTANCE_COSINE / VEC_DISTANCE_EUCLIDEAN with MHNSW indexing
  • Full-text keyword search via MATCH ... AGAINST (IN NATURAL LANGUAGE MODE) on a FULLTEXT index
  • Haystack metadata filtering converted to JSON_UNQUOTE(JSON_EXTRACT(...)) SQL expressions with parameterized queries
  • MariaDBEmbeddingRetriever and MariaDBKeywordRetriever with FilterPolicy support
  • DuplicatePolicy support: FAIL (INSERT), OVERWRITE (upsert via ON DUPLICATE KEY UPDATE), SKIP (INSERT IGNORE)
  • Lazy connection with reconnect on ping failure

Tests

80 tests total all passing:

  • 68 unit tests (mocked DB, no external dependency)
  • 12 integration tests verified against a real MariaDB 11.7 Docker container

CI

Added .github/workflows/mariadb.yml with a MariaDB 11.7 service container, matching the pattern used by pgvector.

How to run locally

docker run -d --name mariadb-haystack \
  -e MARIADB_ROOT_PASSWORD=password \
  -e MARIADB_DATABASE=haystack \
  -p 3306:3306 mariadb:11.7

cd integrations/mariadb
pip install -e .
MARIADB_USER=root MARIADB_PASSWORD=password pytest tests/ -m integration

@SyedShahmeerAli12
SyedShahmeerAli12 requested a review from a team as a code owner July 8, 2026 13:59
@SyedShahmeerAli12
SyedShahmeerAli12 requested review from anakin87 and removed request for a team July 8, 2026 13:59
@github-actions github-actions Bot added topic:CI integration:tavily type:documentation Improvements or additions to documentation labels Jul 8, 2026
@socket-security

socket-security Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedpypi/​mariadb@​1.1.149810010010070

View full report

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Coverage report (tavily)

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  integrations/tavily/src/haystack_integrations/components/fetchers/tavily
  tavily_fetcher.py
Project Total  

This report was generated by python-coverage-comment-action

Implements MariaDBDocumentStore backed by MariaDB 11.7+ native VECTOR
support with MHNSW indexing and full-text keyword search.

- Full DocumentStore protocol: write_documents (FAIL/OVERWRITE/SKIP),
  filter_documents, delete_documents, count_documents
- Vector similarity via VEC_DISTANCE_COSINE / VEC_DISTANCE_EUCLIDEAN
- Full-text keyword search via MATCH ... AGAINST (NATURAL LANGUAGE MODE)
- Haystack metadata filtering converted to JSON_EXTRACT SQL expressions
- MariaDBEmbeddingRetriever and MariaDBKeywordRetriever with FilterPolicy
- 80 tests: 68 unit + 12 integration (all verified against MariaDB 11.7)
- GitHub Actions workflow with MariaDB 11.7 service container

Closes deepset-ai#2340
- Make mariadb C extension import lazy so API reference builds without
  requiring libmariadb-dev in the docs environment
- Fix Docker health check to use --su-mysql flag required by MariaDB 11.7
- Add mariadb (LGPL-2.1) to license compliance exclusion list
@SyedShahmeerAli12
SyedShahmeerAli12 force-pushed the feat/mariadb-document-store-2340 branch from f71d1cd to ff12b6a Compare July 8, 2026 14:09
- Add skip-install=true to default hatch env so docs build does not
  attempt to compile the mariadb C extension (libmariadb-dev not
  available in the API reference runner). The pydoc search_path already
  points to src/ so modules are importable without installation.
- Switch service container health check from healthcheck.sh (unreliable
  in some MariaDB 11.7 images) to mysqladmin ping which is more robust.
…THCHECK

The mariadb:11.7 Docker image ships with a HEALTHCHECK instruction.
GitHub Actions automatically waits for it when no custom options override it.
Custom health-cmd variants (healthcheck.sh, mysqladmin) were failing because
the slim runner environment handles them differently.

@anakin87 anakin87 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I took a first look and found some points to address and some others to discuss.

Comment thread integrations/mariadb/CHANGELOG.md Outdated
Comment thread integrations/mariadb/README.md Outdated
Comment on lines +49 to +50
# skip-install prevents hatch from installing the project (and thus the mariadb C extension)
# in the docs environment. The pydoc search_path points to src/ so modules are found directly.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

what's the problem here?

@SyedShahmeerAli12 SyedShahmeerAli12 Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

mariadb==1.1.14 uses distutils internally, which is removed in Python 3.14 setuptools provides the shim to keep the test env working.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since users will need packaging to use mariadb, I'd add this package to main dependencies (not test). Does it make sense?

Comment thread integrations/mariadb/tests/test_document_store.py
blob_mime_type VARCHAR(255),
meta JSON,
FULLTEXT KEY content_ft_idx (content)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should also set the distance function at table creation.

Also, let's make distance not changeable after table creation:

Declare DISTANCE explicitly. The default is euclidean, and a query using a different distance function than the one the index was built for cannot use the index, it falls back to a full table scan.

See https://mariadb.com/docs/server/reference/sql-structure/vectors/create-table-with-vectors

{where_clause}
ORDER BY score DESC
LIMIT ?
"""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this might also return irrelevant documents if relevant ones are less than top_k
we should also apply matching on WHERE or filtering by score

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

unattended

@SyedShahmeerAli12

Copy link
Copy Markdown
Contributor Author

Addressed all the straightforward review comments. The HNSW index design (create_vector_index flag) and the lazy import approach are still open for discussion

@anakin87 anakin87 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There are still some comments to address.

Please request my review when they are fixed. In the meantime, ask questions if needed.

@SyedShahmeerAli12
SyedShahmeerAli12 force-pushed the feat/mariadb-document-store-2340 branch from 93e2728 to 8f91d92 Compare July 23, 2026 10:10
@SyedShahmeerAli12

SyedShahmeerAli12 commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

ruff auto-detects mariadb and haystack as separate import sections, so import mariadb must go in its own block after all from haystack imports.
Every attempt I made grouped them together, which ruff kept rejecting until I let --fix show me the exact layout it expected.

@SyedShahmeerAli12

Copy link
Copy Markdown
Contributor Author

I mistakently Referenced some PRs here , Well I have cleaned the mess the Code is opened for review

"""


class MariaDBDocumentStore(DocumentStore):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
class MariaDBDocumentStore(DocumentStore):
class MariaDBDocumentStore:

DocumentStore is a Python protocol. We generally don't inherit from it.
To stick to the protocol, only implementing the necessary methods is required (which you're already doing).

meta JSON,
FULLTEXT KEY content_ft_idx (content),
VECTOR INDEX vec_idx (embedding) COMMENT 'MHNSW(distance={distance})'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

filters: dict[str, Any] | None = None,
top_k: int = 10,
score_threshold: float | None = None,
vector_function: str | None = None,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Searches using a different distance function will not be able to use a vector index

I'd simply not allow users to change the distance function at runtime, in other words by removing this parameter

Comment on lines +131 to +132
user: Secret | str = Secret.from_env_var("MARIADB_USER"),
password: Secret | str = Secret.from_env_var("MARIADB_PASSWORD"),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
user: Secret | str = Secret.from_env_var("MARIADB_USER"),
password: Secret | str = Secret.from_env_var("MARIADB_PASSWORD"),
user: Secret = Secret.from_env_var("MARIADB_USER"),
password: Secret = Secret.from_env_var("MARIADB_PASSWORD"),

We don't want to support strings

Comment on lines +28 to +30
# ---------------------------------------------------------------------------
# Helper: build a store with a mocked DB connection
# ---------------------------------------------------------------------------

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
# ---------------------------------------------------------------------------
# Helper: build a store with a mocked DB connection
# ---------------------------------------------------------------------------

Remove all these separation comments

@anakin87 anakin87 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There are still a few rough edges to address in this PR, including some points that were left unresolved from the previous review.

Since this is a new integration, I'd like to see a more thorough pass: try it yourself, refine the implementation, and make sure to address the existing feedback.
Otherwise, I may need to deprioritize further review.

@SyedShahmeerAli12

Copy link
Copy Markdown
Contributor Author

Hi @anakin87 , I've addressed all of your review comments:

  • Removed DocumentStore protocol inheritance
  • Fixed the import order
  • Updated the vector index SQL to use VECTOR INDEX (embedding) (removed COMMENT 'MHNSW(...)')
  • Added HAVING score > 0 to the keyword search to filter out zero-score results
  • Changed user/password to use Secret only (removed the plain string fallback)
  • Removed the vector_function parameter from _embedding_retrieval (and the retriever)
  • Moved packaging>=21.3 to the main dependencies
  • Removed all section separator comments from the tests
  • Updated all test fixtures to use Secret.from_token()

I also verified everything against a real MariaDB 11.7 Docker instance all 120 tests are passing (65 unit + 55 integration).

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

Labels

integration:tavily topic:CI type:documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants