pgvector-haystack 2.0.0__tar.gz → 3.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/CHANGELOG.md +135 -121
  2. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/PKG-INFO +3 -4
  3. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/pyproject.toml +3 -4
  4. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/src/haystack_integrations/document_stores/pgvector/document_store.py +21 -32
  5. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/tests/test_document_store.py +47 -0
  6. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/.gitignore +0 -0
  7. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/LICENSE.txt +0 -0
  8. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/README.md +0 -0
  9. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/examples/embedding_retrieval.py +0 -0
  10. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/examples/hybrid_retrieval.py +0 -0
  11. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/pydoc/config.yml +0 -0
  12. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/src/haystack_integrations/components/retrievers/pgvector/__init__.py +0 -0
  13. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/src/haystack_integrations/components/retrievers/pgvector/embedding_retriever.py +0 -0
  14. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/src/haystack_integrations/components/retrievers/pgvector/keyword_retriever.py +0 -0
  15. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/src/haystack_integrations/document_stores/pgvector/__init__.py +0 -0
  16. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/src/haystack_integrations/document_stores/pgvector/filters.py +0 -0
  17. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/tests/__init__.py +0 -0
  18. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/tests/conftest.py +0 -0
  19. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/tests/test_embedding_retrieval.py +0 -0
  20. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/tests/test_filters.py +0 -0
  21. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/tests/test_keyword_retrieval.py +0 -0
  22. {pgvector_haystack-2.0.0 → pgvector_haystack-3.0.1}/tests/test_retrievers.py +0 -0
@@ -1,121 +1,135 @@
1
- # Changelog
2
-
3
- ## [integrations/pgvector-v1.3.0] - 2025-02-03
4
-
5
- ### 🚀 Features
6
-
7
- - Pgvector - add like and not like filters (#1341)
8
-
9
- ### 🧹 Chores
10
-
11
- - Inherit from `FilterDocumentsTestWithDataframe` in Document Stores (#1290)
12
-
13
-
14
- ## [integrations/pgvector-v1.2.1] - 2025-01-10
15
-
16
- ### 🐛 Bug Fixes
17
-
18
- - PgvectorDocumentStore - use appropriate schema name if dropping index (#1277)
19
-
20
-
21
- ## [integrations/pgvector-v1.2.0] - 2024-11-22
22
-
23
- ### 🚀 Features
24
-
25
- - Add `create_extension` parameter to control vector extension creation (#1213)
26
-
27
-
28
- ## [integrations/pgvector-v1.1.0] - 2024-11-21
29
-
30
- ### 🚀 Features
31
-
32
- - Add filter_policy to pgvector integration (#820)
33
- - Add schema support to pgvector document store. (#1095)
34
- - Pgvector - recreate the connection if it is no longer valid (#1202)
35
-
36
- ### 🐛 Bug Fixes
37
-
38
- - `PgVector` - Fallback to default filter policy when deserializing retrievers without the init parameter (#900)
39
-
40
- ### 📚 Documentation
41
-
42
- - Explain different connection string formats in the docstring (#1132)
43
-
44
- ### 🧪 Testing
45
-
46
- - Do not retry tests in `hatch run test` command (#954)
47
-
48
- ### ⚙️ CI
49
-
50
- - Retry tests to reduce flakyness (#836)
51
- - Adopt uv as installer (#1142)
52
-
53
- ### 🧹 Chores
54
-
55
- - Update ruff invocation to include check parameter (#853)
56
- - PgVector - remove legacy filter support (#1068)
57
- - Update changelog after removing legacy filters (#1083)
58
- - Update ruff linting scripts and settings (#1105)
59
-
60
- ### 🌀 Miscellaneous
61
-
62
- - Ci: install `pytest-rerunfailures` where needed; add retry config to `test-cov` script (#845)
63
- - Chore: Minor retriever pydoc fix (#884)
64
- - Chore: Update pgvector test for the new `apply_filter_policy` usage (#970)
65
- - Chore: pgvector ruff update, don't ruff tests (#984)
66
-
67
- ## [integrations/pgvector-v0.4.0] - 2024-06-20
68
-
69
- ### 🚀 Features
70
-
71
- - Defer the database connection to when it's needed (#773)
72
- - Add customizable index names for pgvector (#818)
73
-
74
- ### 🌀 Miscellaneous
75
-
76
- - Docs: add missing api references (#728)
77
- - [deepset-ai/haystack-core-integrations#727] (#738)
78
-
79
- ## [integrations/pgvector-v0.2.0] - 2024-05-08
80
-
81
- ### 🚀 Features
82
-
83
- - `MongoDBAtlasEmbeddingRetriever` (#427)
84
- - Implement keyword retrieval for pgvector integration (#644)
85
-
86
- ### 🐛 Bug Fixes
87
-
88
- - Fix order of API docs (#447)
89
-
90
- ### 📚 Documentation
91
-
92
- - Update category slug (#442)
93
- - Disable-class-def (#556)
94
-
95
- ### 🌀 Miscellaneous
96
-
97
- - Pgvector - review docstrings and API reference (#502)
98
- - Refactor tests (#574)
99
- - Remove references to Python 3.7 (#601)
100
- - Make Document Stores initially skip `SparseEmbedding` (#606)
101
- - Chore: add license classifiers (#680)
102
- - Type hints in pgvector document store updated for 3.8 compability (#704)
103
- - Chore: change the pydoc renderer class (#718)
104
-
105
- ## [integrations/pgvector-v0.1.0] - 2024-02-14
106
-
107
- ### 🐛 Bug Fixes
108
-
109
- - Pgvector: fix linting (#328)
110
-
111
- ### 🌀 Miscellaneous
112
-
113
- - Pgvector Document Store - minimal implementation (#239)
114
- - Pgvector - filters (#257)
115
- - Pgvector - embedding retrieval (#298)
116
- - Pgvector - Embedding Retriever (#320)
117
- - Pgvector: generate API docs (#325)
118
- - Pgvector: add an example (#334)
119
- - Adopt `Secret` to pgvector (#402)
120
-
121
- <!-- generated by git-cliff -->
1
+ # Changelog
2
+
3
+ ## [integrations/pgvector-v3.0.0] - 2025-03-11
4
+
5
+ ### 🧹 Chores
6
+
7
+ - Remove Python 3.8 support (#1421)
8
+ - Use Haystack logging across integrations (#1484)
9
+ - Pgvector - pin haystack and remove dataframe checks (#1518)
10
+
11
+ ## [integrations/pgvector-v2.0.0] - 2025-02-13
12
+
13
+ ### 🧹 Chores
14
+
15
+ - Pgvector - remove support for dataframe (#1370)
16
+
17
+ ## [integrations/pgvector-v1.3.0] - 2025-02-03
18
+
19
+ ### 🚀 Features
20
+
21
+ - Pgvector - add like and not like filters (#1341)
22
+
23
+ ### 🧹 Chores
24
+
25
+ - Inherit from `FilterDocumentsTestWithDataframe` in Document Stores (#1290)
26
+
27
+
28
+ ## [integrations/pgvector-v1.2.1] - 2025-01-10
29
+
30
+ ### 🐛 Bug Fixes
31
+
32
+ - PgvectorDocumentStore - use appropriate schema name if dropping index (#1277)
33
+
34
+
35
+ ## [integrations/pgvector-v1.2.0] - 2024-11-22
36
+
37
+ ### 🚀 Features
38
+
39
+ - Add `create_extension` parameter to control vector extension creation (#1213)
40
+
41
+
42
+ ## [integrations/pgvector-v1.1.0] - 2024-11-21
43
+
44
+ ### 🚀 Features
45
+
46
+ - Add filter_policy to pgvector integration (#820)
47
+ - Add schema support to pgvector document store. (#1095)
48
+ - Pgvector - recreate the connection if it is no longer valid (#1202)
49
+
50
+ ### 🐛 Bug Fixes
51
+
52
+ - `PgVector` - Fallback to default filter policy when deserializing retrievers without the init parameter (#900)
53
+
54
+ ### 📚 Documentation
55
+
56
+ - Explain different connection string formats in the docstring (#1132)
57
+
58
+ ### 🧪 Testing
59
+
60
+ - Do not retry tests in `hatch run test` command (#954)
61
+
62
+ ### ⚙️ CI
63
+
64
+ - Retry tests to reduce flakyness (#836)
65
+ - Adopt uv as installer (#1142)
66
+
67
+ ### 🧹 Chores
68
+
69
+ - Update ruff invocation to include check parameter (#853)
70
+ - PgVector - remove legacy filter support (#1068)
71
+ - Update changelog after removing legacy filters (#1083)
72
+ - Update ruff linting scripts and settings (#1105)
73
+
74
+ ### 🌀 Miscellaneous
75
+
76
+ - Ci: install `pytest-rerunfailures` where needed; add retry config to `test-cov` script (#845)
77
+ - Chore: Minor retriever pydoc fix (#884)
78
+ - Chore: Update pgvector test for the new `apply_filter_policy` usage (#970)
79
+ - Chore: pgvector ruff update, don't ruff tests (#984)
80
+
81
+ ## [integrations/pgvector-v0.4.0] - 2024-06-20
82
+
83
+ ### 🚀 Features
84
+
85
+ - Defer the database connection to when it's needed (#773)
86
+ - Add customizable index names for pgvector (#818)
87
+
88
+ ### 🌀 Miscellaneous
89
+
90
+ - Docs: add missing api references (#728)
91
+ - [deepset-ai/haystack-core-integrations#727] (#738)
92
+
93
+ ## [integrations/pgvector-v0.2.0] - 2024-05-08
94
+
95
+ ### 🚀 Features
96
+
97
+ - `MongoDBAtlasEmbeddingRetriever` (#427)
98
+ - Implement keyword retrieval for pgvector integration (#644)
99
+
100
+ ### 🐛 Bug Fixes
101
+
102
+ - Fix order of API docs (#447)
103
+
104
+ ### 📚 Documentation
105
+
106
+ - Update category slug (#442)
107
+ - Disable-class-def (#556)
108
+
109
+ ### 🌀 Miscellaneous
110
+
111
+ - Pgvector - review docstrings and API reference (#502)
112
+ - Refactor tests (#574)
113
+ - Remove references to Python 3.7 (#601)
114
+ - Make Document Stores initially skip `SparseEmbedding` (#606)
115
+ - Chore: add license classifiers (#680)
116
+ - Type hints in pgvector document store updated for 3.8 compability (#704)
117
+ - Chore: change the pydoc renderer class (#718)
118
+
119
+ ## [integrations/pgvector-v0.1.0] - 2024-02-14
120
+
121
+ ### 🐛 Bug Fixes
122
+
123
+ - Pgvector: fix linting (#328)
124
+
125
+ ### 🌀 Miscellaneous
126
+
127
+ - Pgvector Document Store - minimal implementation (#239)
128
+ - Pgvector - filters (#257)
129
+ - Pgvector - embedding retrieval (#298)
130
+ - Pgvector - Embedding Retriever (#320)
131
+ - Pgvector: generate API docs (#325)
132
+ - Pgvector: add an example (#334)
133
+ - Adopt `Secret` to pgvector (#402)
134
+
135
+ <!-- generated by git-cliff -->
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pgvector-haystack
3
- Version: 2.0.0
3
+ Version: 3.0.1
4
4
  Summary: An integration of pgvector (vector search extension for Postgres) with Haystack
5
5
  Project-URL: Source, https://github.com/deepset-ai/haystack-core-integrations
6
6
  Project-URL: Documentation, https://github.com/deepset-ai/haystack-core-integrations/blob/main/integrations/pgvector/README.md
@@ -11,15 +11,14 @@ License-File: LICENSE.txt
11
11
  Classifier: Development Status :: 4 - Beta
12
12
  Classifier: License :: OSI Approved :: Apache Software License
13
13
  Classifier: Programming Language :: Python
14
- Classifier: Programming Language :: Python :: 3.8
15
14
  Classifier: Programming Language :: Python :: 3.9
16
15
  Classifier: Programming Language :: Python :: 3.10
17
16
  Classifier: Programming Language :: Python :: 3.11
18
17
  Classifier: Programming Language :: Python :: 3.12
19
18
  Classifier: Programming Language :: Python :: Implementation :: CPython
20
19
  Classifier: Programming Language :: Python :: Implementation :: PyPy
21
- Requires-Python: >=3.8
22
- Requires-Dist: haystack-ai
20
+ Requires-Python: >=3.9
21
+ Requires-Dist: haystack-ai>=2.11.0
23
22
  Requires-Dist: pgvector
24
23
  Requires-Dist: psycopg[binary]
25
24
  Description-Content-Type: text/markdown
@@ -7,7 +7,7 @@ name = "pgvector-haystack"
7
7
  dynamic = ["version"]
8
8
  description = "An integration of pgvector (vector search extension for Postgres) with Haystack"
9
9
  readme = "README.md"
10
- requires-python = ">=3.8"
10
+ requires-python = ">=3.9"
11
11
  license = "Apache-2.0"
12
12
  keywords = []
13
13
  authors = [{ name = "deepset GmbH", email = "info@deepset.ai" }]
@@ -15,7 +15,6 @@ classifiers = [
15
15
  "License :: OSI Approved :: Apache Software License",
16
16
  "Development Status :: 4 - Beta",
17
17
  "Programming Language :: Python",
18
- "Programming Language :: Python :: 3.8",
19
18
  "Programming Language :: Python :: 3.9",
20
19
  "Programming Language :: Python :: 3.10",
21
20
  "Programming Language :: Python :: 3.11",
@@ -23,7 +22,7 @@ classifiers = [
23
22
  "Programming Language :: Python :: Implementation :: CPython",
24
23
  "Programming Language :: Python :: Implementation :: PyPy",
25
24
  ]
26
- dependencies = ["haystack-ai", "pgvector", "psycopg[binary]"]
25
+ dependencies = ["haystack-ai>=2.11.0", "pgvector", "psycopg[binary]"]
27
26
 
28
27
  [project.urls]
29
28
  Source = "https://github.com/deepset-ai/haystack-core-integrations"
@@ -60,7 +59,7 @@ cov-retry = ["test-cov-retry", "cov-report"]
60
59
  docs = ["pydoc-markdown pydoc/config.yml"]
61
60
 
62
61
  [[tool.hatch.envs.all.matrix]]
63
- python = ["3.8", "3.9", "3.10", "3.11", "3.12"]
62
+ python = [ "3.9", "3.10", "3.11", "3.12"]
64
63
 
65
64
  [tool.hatch.envs.lint]
66
65
  installer = "uv"
@@ -1,10 +1,9 @@
1
1
  # SPDX-FileCopyrightText: 2023-present deepset GmbH <info@deepset.ai>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
- import logging
5
4
  from typing import Any, Dict, List, Literal, Optional
6
5
 
7
- from haystack import default_from_dict, default_to_dict
6
+ from haystack import default_from_dict, default_to_dict, logging
8
7
  from haystack.dataclasses.document import ByteStream, Document
9
8
  from haystack.document_stores.errors import DocumentStoreError, DuplicateDocumentError
10
9
  from haystack.document_stores.types import DuplicatePolicy
@@ -24,7 +23,7 @@ from .filters import _convert_filters_to_where_clause_and_params
24
23
  logger = logging.getLogger(__name__)
25
24
 
26
25
  CREATE_TABLE_STATEMENT = """
27
- CREATE TABLE IF NOT EXISTS {schema_name}.{table_name} (
26
+ CREATE TABLE {schema_name}.{table_name} (
28
27
  id VARCHAR(128) PRIMARY KEY,
29
28
  embedding VECTOR({embedding_dimension}),
30
29
  content TEXT,
@@ -193,7 +192,7 @@ class PgvectorDocumentStore:
193
192
  try:
194
193
  self._connection.close()
195
194
  except Error as e:
196
- logger.debug("Failed to close connection: %s", str(e))
195
+ logger.debug("Failed to close connection: {e}", e=str(e))
197
196
 
198
197
  conn_str = self.connection_string.resolve_value() or ""
199
198
  connection = connect(conn_str)
@@ -295,7 +294,7 @@ class PgvectorDocumentStore:
295
294
  cursor = cursor or self.cursor
296
295
 
297
296
  sql_query_str = sql_query.as_string(cursor) if not isinstance(sql_query, str) else sql_query
298
- logger.debug("SQL query: %s\nParameters: %s", sql_query_str, params)
297
+ logger.debug("SQL query: {query}\nParameters: {parameters}", query=sql_query_str, parameters=params)
299
298
 
300
299
  try:
301
300
  result = cursor.execute(sql_query, params)
@@ -311,13 +310,22 @@ class PgvectorDocumentStore:
311
310
  Creates the table to store Haystack documents if it doesn't exist yet.
312
311
  """
313
312
 
314
- create_sql = SQL(CREATE_TABLE_STATEMENT).format(
315
- schema_name=Identifier(self.schema_name),
316
- table_name=Identifier(self.table_name),
317
- embedding_dimension=SQLLiteral(self.embedding_dimension),
313
+ table_exists = bool(
314
+ self._execute_sql(
315
+ "SELECT 1 FROM pg_tables WHERE schemaname = %s AND tablename = %s",
316
+ (self.schema_name, self.table_name),
317
+ "Could not check if table exists",
318
+ ).fetchone()
318
319
  )
319
320
 
320
- self._execute_sql(create_sql, error_msg="Could not create table in PgvectorDocumentStore")
321
+ if not table_exists:
322
+ create_sql = SQL(CREATE_TABLE_STATEMENT).format(
323
+ schema_name=Identifier(self.schema_name),
324
+ table_name=Identifier(self.table_name),
325
+ embedding_dimension=SQLLiteral(self.embedding_dimension),
326
+ )
327
+
328
+ self._execute_sql(create_sql, error_msg="Could not create table in PgvectorDocumentStore")
321
329
 
322
330
  def delete_table(self):
323
331
  """
@@ -512,7 +520,7 @@ class PgvectorDocumentStore:
512
520
  sql_insert += SQL(" RETURNING id")
513
521
 
514
522
  sql_query_str = sql_insert.as_string(self.cursor) if not isinstance(sql_insert, str) else sql_insert
515
- logger.debug("SQL query: %s\nParameters: %s", sql_query_str, db_documents)
523
+ logger.debug("SQL query: {query}\nParameters: {parameters}", query=sql_query_str, parameters=db_documents)
516
524
 
517
525
  try:
518
526
  self.cursor.executemany(sql_insert, db_documents, returning=True)
@@ -555,24 +563,14 @@ class PgvectorDocumentStore:
555
563
  db_document["blob_mime_type"] = blob.mime_type if blob and blob.mime_type else None
556
564
  db_document["meta"] = Jsonb(db_document["meta"])
557
565
 
558
- if "dataframe" in db_document:
559
- dataframe = db_document.pop("dataframe", None)
560
- if dataframe:
561
- logger.warning(
562
- "Document %s has the `dataframe` field set. "
563
- "PgvectorDocumentStore no longer supports dataframes and this field will be ignored. "
564
- "The `dataframe` field will soon be removed from Haystack Document.",
565
- db_document["id"],
566
- )
567
-
568
566
  if "sparse_embedding" in db_document:
569
567
  sparse_embedding = db_document.pop("sparse_embedding", None)
570
568
  if sparse_embedding:
571
569
  logger.warning(
572
- "Document %s has the `sparse_embedding` field set,"
570
+ "Document {doc_id} has the `sparse_embedding` field set,"
573
571
  "but storing sparse embeddings in Pgvector is not currently supported."
574
572
  "The `sparse_embedding` field will be ignored.",
575
- db_document["id"],
573
+ doc_id=db_document["id"],
576
574
  )
577
575
 
578
576
  db_documents.append(db_document)
@@ -591,20 +589,11 @@ class PgvectorDocumentStore:
591
589
  blob_data = haystack_dict.pop("blob_data")
592
590
  blob_meta = haystack_dict.pop("blob_meta")
593
591
  blob_mime_type = haystack_dict.pop("blob_mime_type")
594
- dataframe = haystack_dict.pop("dataframe", None)
595
592
 
596
593
  # convert the embedding to a list of floats
597
594
  if document.get("embedding") is not None:
598
595
  haystack_dict["embedding"] = document["embedding"].tolist()
599
596
 
600
- if dataframe:
601
- logger.warning(
602
- "Document %s has the `dataframe` field set. "
603
- "PgvectorDocumentStore no longer supports dataframes and this field will be ignored. "
604
- "The `dataframe` field will soon be removed from Haystack Document.",
605
- haystack_dict["id"],
606
- )
607
-
608
597
  haystack_document = Document.from_dict(haystack_dict)
609
598
 
610
599
  if blob_data:
@@ -288,3 +288,50 @@ def test_hnsw_index_recreation():
288
288
 
289
289
  # verify that oids differ
290
290
  assert second_oid != first_oid, "Index was not recreated (OID remained the same)"
291
+
292
+ # Clean up: drop the schema after the test
293
+ with psycopg.connect(connection_string, autocommit=True) as conn:
294
+ conn.execute(f"DROP SCHEMA IF EXISTS {schema_name} CASCADE")
295
+
296
+
297
+ @pytest.mark.integration
298
+ def test_create_table_if_not_exists():
299
+ def get_table_oid(document_store, schema_name, table_name):
300
+ sql_get_table_oid = """
301
+ SELECT c.oid
302
+ FROM pg_class c
303
+ JOIN pg_namespace n ON n.oid = c.relnamespace
304
+ WHERE c.relkind = 'r'
305
+ AND n.nspname = %s
306
+ AND c.relname = %s;
307
+ """
308
+ return document_store.cursor.execute(sql_get_table_oid, (schema_name, table_name)).fetchone()[0]
309
+
310
+ connection_string = "postgresql://postgres:postgres@localhost:5432/postgres"
311
+ schema_name = "test_schema"
312
+ table_name = "test_table"
313
+
314
+ # Create a new schema
315
+ with psycopg.connect(connection_string, autocommit=True) as conn:
316
+ conn.execute(f"CREATE SCHEMA {schema_name}")
317
+
318
+ document_store = PgvectorDocumentStore(
319
+ connection_string=Secret.from_token(connection_string),
320
+ schema_name=schema_name,
321
+ table_name=table_name,
322
+ )
323
+
324
+ document_store._create_table_if_not_exists()
325
+
326
+ first_table_oid = get_table_oid(document_store, schema_name, table_name)
327
+ assert first_table_oid is not None, "Table was not created"
328
+
329
+ document_store._create_table_if_not_exists()
330
+
331
+ second_table_oid = get_table_oid(document_store, schema_name, table_name)
332
+
333
+ assert first_table_oid == second_table_oid, "Table was recreated"
334
+
335
+ # Clean up: drop the schema after the test
336
+ with psycopg.connect(connection_string, autocommit=True) as conn:
337
+ conn.execute(f"DROP SCHEMA IF EXISTS {schema_name} CASCADE")