echoss-db 1.2.4__tar.gz → 2.2.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.
- {echoss_db-1.2.4 → echoss_db-2.2.1}/MANIFEST.in +3 -3
- echoss_db-2.2.1/PKG-INFO +598 -0
- echoss_db-2.2.1/README.md +567 -0
- {echoss_db-1.2.4 → echoss_db-2.2.1}/echoss_db/elastic_search.py +7 -1
- echoss_db-2.2.1/echoss_db/mapping/__init__.py +11 -0
- echoss_db-2.2.1/echoss_db/mapping/dataclass_mapper.py +35 -0
- echoss_db-2.2.1/echoss_db/mapping/errors.py +6 -0
- echoss_db-2.2.1/echoss_db/mapping/param_mapper.py +28 -0
- echoss_db-2.2.1/echoss_db/mapping/pydantic_mapper.py +43 -0
- echoss_db-2.2.1/echoss_db/mapping/row_mapper.py +34 -0
- echoss_db-2.2.1/echoss_db/mapping/types.py +4 -0
- {echoss_db-1.2.4 → echoss_db-2.2.1}/echoss_db/mongo_query.py +24 -0
- {echoss_db-1.2.4 → echoss_db-2.2.1}/echoss_db/mysql_query.py +15 -1
- {echoss_db-1.2.4 → echoss_db-2.2.1}/echoss_db/postgres_query.py +201 -7
- {echoss_db-1.2.4 → echoss_db-2.2.1}/echoss_db/qdrant_vector.py +168 -31
- echoss_db-2.2.1/echoss_db/sql_transaction.py +169 -0
- echoss_db-2.2.1/echoss_db.egg-info/PKG-INFO +598 -0
- echoss_db-2.2.1/echoss_db.egg-info/SOURCES.txt +46 -0
- echoss_db-2.2.1/echoss_db.egg-info/requires.txt +18 -0
- echoss_db-2.2.1/echoss_db.egg-info/top_level.txt +4 -0
- echoss_db-2.2.1/pyproject.toml +46 -0
- {echoss_db-1.2.4 → echoss_db-2.2.1}/requirements.txt +2 -3
- echoss_db-2.2.1/tests/__init__.py +0 -0
- echoss_db-2.2.1/tests/integration/__init__.py +0 -0
- echoss_db-2.2.1/tests/integration/conftest.py +65 -0
- echoss_db-2.2.1/tests/integration/test_postgres_integration.py +98 -0
- echoss_db-2.2.1/tests/integration/test_qdrant_integration.py +66 -0
- echoss_db-2.2.1/tests/manual/__init__.py +0 -0
- echoss_db-2.2.1/tests/manual/_postgres_test_schema.py +14 -0
- {echoss_db-1.2.4/tutorial → echoss_db-2.2.1/tests/manual}/example_elasticsearch.py +3 -2
- echoss_db-2.2.1/tests/manual/example_mapping_mysql.py +91 -0
- {echoss_db-1.2.4/tutorial → echoss_db-2.2.1/tests/manual}/example_mongo.py +2 -4
- {echoss_db-1.2.4/tutorial → echoss_db-2.2.1/tests/manual}/example_mysql.py +2 -2
- {echoss_db-1.2.4/tutorial → echoss_db-2.2.1/tests/manual}/example_postgres.py +8 -3
- {echoss_db-1.2.4/tutorial → echoss_db-2.2.1/tests/manual}/example_postgres_qdrant_ingest.py +9 -4
- {echoss_db-1.2.4/tutorial → echoss_db-2.2.1/tests/manual}/example_qdrant.py +9 -3
- echoss_db-2.2.1/tests/manual/setup_ai_rag_test_schema.sql +34 -0
- echoss_db-2.2.1/tests/unit/__init__.py +0 -0
- echoss_db-2.2.1/tests/unit/mapping/__init__.py +1 -0
- echoss_db-2.2.1/tests/unit/mapping/test_param_mapper.py +48 -0
- echoss_db-1.2.4/PKG-INFO +0 -334
- echoss_db-1.2.4/README.md +0 -301
- echoss_db-1.2.4/echoss_db.egg-info/PKG-INFO +0 -334
- echoss_db-1.2.4/echoss_db.egg-info/SOURCES.txt +0 -26
- echoss_db-1.2.4/echoss_db.egg-info/requires.txt +0 -8
- echoss_db-1.2.4/echoss_db.egg-info/top_level.txt +0 -1
- echoss_db-1.2.4/setup.py +0 -33
- {echoss_db-1.2.4 → echoss_db-2.2.1}/LICENSE +0 -0
- {echoss_db-1.2.4 → echoss_db-2.2.1}/echoss_db/__init__.py +0 -0
- {echoss_db-1.2.4 → echoss_db-2.2.1}/echoss_db.egg-info/dependency_links.txt +0 -0
- {echoss_db-1.2.4 → echoss_db-2.2.1}/package_tests/test_package_imports.py +0 -0
- {echoss_db-1.2.4 → echoss_db-2.2.1}/setup.cfg +0 -0
- {echoss_db-1.2.4/tutorial → echoss_db-2.2.1/tests/manual}/example_elasticsearch.ipynb +0 -0
- {echoss_db-1.2.4/tutorial → echoss_db-2.2.1/tests/manual}/example_mongo.ipynb +0 -0
- {echoss_db-1.2.4/tutorial → echoss_db-2.2.1/tests/manual}/example_mysql.ipynb +0 -0
|
@@ -2,10 +2,10 @@ include README.md
|
|
|
2
2
|
include LICENSE
|
|
3
3
|
include requirements.txt
|
|
4
4
|
exclude config/
|
|
5
|
-
|
|
5
|
+
prune _archive
|
|
6
|
+
recursive-include tests *.py *.ipynb *.sql
|
|
6
7
|
recursive-include package_tests *.py
|
|
7
|
-
recursive-exclude
|
|
8
|
-
recursive-exclude tutorial *.env
|
|
8
|
+
recursive-exclude tests *.env
|
|
9
9
|
recursive-exclude * __pycache__/
|
|
10
10
|
recursive-exclude * *.log *.log.*
|
|
11
11
|
recursive-exclude * .*.un~
|
echoss_db-2.2.1/PKG-INFO
ADDED
|
@@ -0,0 +1,598 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: echoss-db
|
|
3
|
+
Version: 2.2.1
|
|
4
|
+
Summary: echoss AI Bigdata Solution - Database Query Package
|
|
5
|
+
Author-email: ckkim <ckkim@12cm.co.kr>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/12cmlab/echoss-query
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Requires-Python: >=3.12
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: pandas>=1.5.3
|
|
17
|
+
Requires-Dist: sqlalchemy>=2.0.0
|
|
18
|
+
Requires-Dist: PyMySQL>=1.0.2
|
|
19
|
+
Requires-Dist: opensearch-py<3.0.0,>=2.8.0
|
|
20
|
+
Requires-Dist: echoss-fileformat>=1.1.2
|
|
21
|
+
Requires-Dist: psycopg[binary]<4.0.0,>=3.2
|
|
22
|
+
Requires-Dist: qdrant-client[fastembed]<2.0.0,>=1.14.1
|
|
23
|
+
Provides-Extra: mapping
|
|
24
|
+
Requires-Dist: pydantic<3.0.0,>=2.0.0; extra == "mapping"
|
|
25
|
+
Provides-Extra: mongo
|
|
26
|
+
Requires-Dist: pymongo>=4.3.3; extra == "mongo"
|
|
27
|
+
Provides-Extra: qdrant-fastembed
|
|
28
|
+
Provides-Extra: all
|
|
29
|
+
Requires-Dist: pydantic<3.0.0,>=2.0.0; extra == "all"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# echoss_db
|
|
33
|
+
|
|
34
|
+
MySQL, PostgreSQL, OpenSearch, Qdrant compatible query/vector access package
|
|
35
|
+
|
|
36
|
+
> ⚠️ **MongoDB support is deprecated** (v2.2.0) and will be removed in v3.0.0.
|
|
37
|
+
> `pymongo` is now an optional dependency: `pip install echoss-db[mongo]`.
|
|
38
|
+
|
|
39
|
+
## Prepare
|
|
40
|
+
|
|
41
|
+
사용 전 config(인증 정보) 유무를 확인한 뒤 사용해야 합니다.
|
|
42
|
+
`config/config.example.yaml`을 `config/config.yaml`로 복사해 실제 값을 채우세요 (실 config는 gitignore 대상).
|
|
43
|
+
`config/config.yaml` 기준의 credential 제거 예시는 아래와 같습니다.
|
|
44
|
+
|
|
45
|
+
```yaml
|
|
46
|
+
mysql:
|
|
47
|
+
user: <MYSQL_USER>
|
|
48
|
+
passwd: <MYSQL_PASSWORD>
|
|
49
|
+
host: <MYSQL_HOST>
|
|
50
|
+
port: <MYSQL_PORT>
|
|
51
|
+
db: <MYSQL_DB>
|
|
52
|
+
charset: utf8mb4
|
|
53
|
+
|
|
54
|
+
mongo:
|
|
55
|
+
host: <MONGO_HOST>
|
|
56
|
+
port: <MONGO_PORT>
|
|
57
|
+
db: <MONGO_DB>
|
|
58
|
+
|
|
59
|
+
elastic:
|
|
60
|
+
user: <ELASTIC_USER>
|
|
61
|
+
passwd: <ELASTIC_PASSWORD>
|
|
62
|
+
host: <ELASTIC_HOST>
|
|
63
|
+
port: <ELASTIC_PORT>
|
|
64
|
+
scheme: <http|https>
|
|
65
|
+
verify_certs: <true|false>
|
|
66
|
+
|
|
67
|
+
postgres:
|
|
68
|
+
user: <POSTGRES_USER>
|
|
69
|
+
passwd: <POSTGRES_PASSWORD>
|
|
70
|
+
host: <POSTGRES_HOST>
|
|
71
|
+
port: <POSTGRES_PORT>
|
|
72
|
+
db: <POSTGRES_DB>
|
|
73
|
+
schema: <POSTGRES_SCHEMA>
|
|
74
|
+
|
|
75
|
+
qdrant:
|
|
76
|
+
host: <QDRANT_HOST>
|
|
77
|
+
port: <QDRANT_PORT>
|
|
78
|
+
scheme: <http|https>
|
|
79
|
+
timeout: <SECONDS>
|
|
80
|
+
collection: <QDRANT_COLLECTION>
|
|
81
|
+
default_limit: <DEFAULT_LIMIT>
|
|
82
|
+
# fastembed_model omitted -> default FastEmbed model automatically applied
|
|
83
|
+
# fastembed_model: null -> external vector mode (no FastEmbed)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Installation
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Version Line Policy
|
|
91
|
+
|
|
92
|
+
- `echoss-db 1.x`: legacy line for Python `3.9` / `3.10`
|
|
93
|
+
- `echoss-db 2.x`: current line for Python `>=3.12` (last release supporting `3.11`: `2.1.0`)
|
|
94
|
+
- company standard runtime for `2.x`: Python `3.12`
|
|
95
|
+
|
|
96
|
+
Recommended local environments:
|
|
97
|
+
|
|
98
|
+
- `1.x` development / maintenance: `echoss_dev`
|
|
99
|
+
- `2.x` standard development / integration: use a Python `3.12` environment
|
|
100
|
+
|
|
101
|
+
This package currently documents the `2.x` line.
|
|
102
|
+
Python 3.12 is the company standard target runtime.
|
|
103
|
+
Python 3.11 or lower is not supported in `echoss-db>=2.2.0`; use the `1.x` line for legacy Python `3.9` / `3.10` environments.
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
pip install -U echoss-db
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
If your environment previously used legacy PostgreSQL drivers, clean them first:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
pip uninstall -y psycopg2 psycopg2-binary
|
|
113
|
+
pip install -U "psycopg[binary]>=3.2,<4.0.0"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
If you already have an older Pillow in a shared environment, upgrade it before installing:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
pip install -U "Pillow>=10.3.0,<12.0"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Recommended fresh environment examples:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
conda create -n echoss_dev_py312 python=3.12 -y
|
|
126
|
+
conda activate echoss_dev_py312
|
|
127
|
+
pip install -U echoss-db
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Repository-local conda env convention:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# 1.x legacy line
|
|
134
|
+
CONDA_NO_PLUGINS=true conda run -n echoss_dev python --version
|
|
135
|
+
|
|
136
|
+
# 2.x standard runtime
|
|
137
|
+
python3.12 --version
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
For deployment, prefer a dedicated service environment instead of reusing a mixed notebook/UI environment.
|
|
141
|
+
Shared environments can keep stale transitive packages such as Pillow or urllib3 and hide resolver problems until runtime.
|
|
142
|
+
|
|
143
|
+
Optional mapping extras (pydantic):
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
pip install -U "echoss-db[mapping]"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Quick Start
|
|
150
|
+
|
|
151
|
+
### Import package and class
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from echoss_db import MysqlQuery, PostgresQuery, MongoQuery, ElasticSearch, QdrantVector
|
|
155
|
+
|
|
156
|
+
with MysqlQuery('CONFIG_FILE_PATH' or dict) as mysql:
|
|
157
|
+
rows = mysql.select_list("SELECT * FROM users WHERE status=%s", ("active",))
|
|
158
|
+
|
|
159
|
+
with PostgresQuery('CONFIG_FILE_PATH' or dict) as postgres:
|
|
160
|
+
docs = postgres.select_list("SELECT doc_id, content FROM kb_document LIMIT %s", (10,))
|
|
161
|
+
|
|
162
|
+
with MongoQuery('CONFIG_FILE_PATH' or dict) as mongo:
|
|
163
|
+
items = mongo.select_list("sample_collection", {"status": "active"})
|
|
164
|
+
|
|
165
|
+
with ElasticSearch('CONFIG_FILE_PATH' or dict) as elastic:
|
|
166
|
+
hits = elastic.search_list(body={"query": {"match_all": {}}}, fetch_all=False)
|
|
167
|
+
|
|
168
|
+
with QdrantVector('CONFIG_FILE_PATH' or dict) as qdrant:
|
|
169
|
+
hits = qdrant.search_text(query_text="RAG", limit=5)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Lifecycle And Transactions
|
|
173
|
+
|
|
174
|
+
Client-level context manager is recommended for routine usage. It closes the client on block exit, but it does not define a transaction boundary.
|
|
175
|
+
|
|
176
|
+
Direct instantiation also remains valid:
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
mysql = MysqlQuery('CONFIG_FILE_PATH' or dict)
|
|
180
|
+
rows = mysql.select_list("SELECT * FROM users")
|
|
181
|
+
mysql.close()
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
For batch jobs or delayed commit flows, use the explicit SQL transaction API:
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
with MysqlQuery('CONFIG_FILE_PATH' or dict) as mysql:
|
|
188
|
+
with mysql.transaction() as tx:
|
|
189
|
+
tx.insert("INSERT INTO users(name) VALUES (%s)", ("kim",))
|
|
190
|
+
tx.update("UPDATE users SET status=%s WHERE name=%s", ("active", "kim"))
|
|
191
|
+
|
|
192
|
+
with PostgresQuery('CONFIG_FILE_PATH' or dict) as postgres:
|
|
193
|
+
with postgres.transaction() as tx:
|
|
194
|
+
tx.insert(
|
|
195
|
+
"INSERT INTO kb_document(source_type) VALUES (%s) RETURNING doc_id",
|
|
196
|
+
("tutorial",),
|
|
197
|
+
return_lastrowid=True,
|
|
198
|
+
)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Transaction API semantics:
|
|
202
|
+
|
|
203
|
+
- `transaction()` is available only on `MysqlQuery` and `PostgresQuery`
|
|
204
|
+
- transaction-scoped methods are fail-fast and propagate exceptions
|
|
205
|
+
- if an exception leaves the `with ... transaction()` block, rollback is executed automatically
|
|
206
|
+
- if the block exits normally, commit is executed automatically
|
|
207
|
+
- if `tx.commit()` is called manually, the current transaction unit is committed and a new transaction unit starts on the same connection
|
|
208
|
+
- if `tx.rollback()` is called manually, the current transaction unit is rolled back and a new transaction unit starts on the same connection
|
|
209
|
+
|
|
210
|
+
This behavior is intentionally stricter than the legacy convenience methods such as `insert()` / `update()` / `delete()`, which often log and return fallback values instead of raising.
|
|
211
|
+
|
|
212
|
+
### MySQL
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
# CREATE
|
|
218
|
+
mysql.create('QUERY_STRING')
|
|
219
|
+
|
|
220
|
+
# DROP
|
|
221
|
+
mysql.drop('QUERY_STRING')
|
|
222
|
+
|
|
223
|
+
# TRUNCATE
|
|
224
|
+
mysql.truncate('QUERY_STRING')
|
|
225
|
+
|
|
226
|
+
# ALTER
|
|
227
|
+
mysql.alter('QUERY_STRING')
|
|
228
|
+
|
|
229
|
+
# SELECT
|
|
230
|
+
mysql.select('QUERY_STRING', params=None)
|
|
231
|
+
mysql.select_one('QUERY_STRING', params=None)
|
|
232
|
+
mysql.select_list('QUERY_STRING', params=None)
|
|
233
|
+
mysql.faster_select('QUERY_STRING', params=None)
|
|
234
|
+
|
|
235
|
+
# INSERT without params
|
|
236
|
+
mysql.insert('QUERY_STRING', params=None)
|
|
237
|
+
# INSERT with tuple
|
|
238
|
+
mysql.insert('QUERY_STRING', params)
|
|
239
|
+
# INSERT with list[tuple]
|
|
240
|
+
mysql.insert('QUERY_STRING', params_list)
|
|
241
|
+
|
|
242
|
+
# UPDATE
|
|
243
|
+
mysql.update('QUERY_STRING', params=None)
|
|
244
|
+
|
|
245
|
+
# DELETE
|
|
246
|
+
mysql.delete('QUERY_STRING', params=None)
|
|
247
|
+
|
|
248
|
+
# show Database
|
|
249
|
+
mysql.databases()
|
|
250
|
+
|
|
251
|
+
# show Tables
|
|
252
|
+
mysql.tables()
|
|
253
|
+
|
|
254
|
+
# Ping
|
|
255
|
+
mysql.ping()
|
|
256
|
+
|
|
257
|
+
# Close
|
|
258
|
+
# crash process close
|
|
259
|
+
mysql.close()
|
|
260
|
+
|
|
261
|
+
# debug query : default True
|
|
262
|
+
mysql.query_debug(False)
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### PostgreSQL
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
```python
|
|
270
|
+
# CREATE
|
|
271
|
+
postgres.create('QUERY_STRING')
|
|
272
|
+
|
|
273
|
+
# DROP
|
|
274
|
+
postgres.drop('QUERY_STRING')
|
|
275
|
+
|
|
276
|
+
# TRUNCATE
|
|
277
|
+
postgres.truncate('QUERY_STRING')
|
|
278
|
+
|
|
279
|
+
# ALTER
|
|
280
|
+
postgres.alter('QUERY_STRING')
|
|
281
|
+
|
|
282
|
+
# SELECT
|
|
283
|
+
postgres.select('QUERY_STRING', params=None)
|
|
284
|
+
postgres.select_one('QUERY_STRING', params=None)
|
|
285
|
+
postgres.select_list('QUERY_STRING', params=None)
|
|
286
|
+
postgres.faster_select('QUERY_STRING', params=None, fetch_size=1000)
|
|
287
|
+
postgres.faster_select_generator('QUERY_STRING', params=None, fetch_size=1000)
|
|
288
|
+
|
|
289
|
+
# SELECT with JSONB normalization
|
|
290
|
+
# JSONB 컬럼은 드라이버/환경에 따라 str 또는 dict로 반환됩니다(반환 타입 비결정적).
|
|
291
|
+
# parse_json으로 항상 dict/list로 정규화하여 호출부의 방어적 파싱을 제거합니다.
|
|
292
|
+
postgres.select('SELECT id, detail_json FROM t', parse_json=['detail_json']) # 지정 컬럼만
|
|
293
|
+
postgres.select('SELECT * FROM t', parse_json=True) # 모든 컬럼의 JSON-like str 시도
|
|
294
|
+
# 기본 parse_json=False는 기존 동작과 동일(하위호환)
|
|
295
|
+
# transaction 경로도 동일 지원: tx.select(..., parse_json=[...])
|
|
296
|
+
|
|
297
|
+
# INSERT
|
|
298
|
+
postgres.insert('QUERY_STRING', params=None)
|
|
299
|
+
postgres.insert('QUERY_STRING', params=None, return_lastrowid=True)
|
|
300
|
+
|
|
301
|
+
# UPSERT (INSERT ... ON CONFLICT) — ON CONFLICT 절 자동 생성
|
|
302
|
+
# 단일 dict 또는 list[dict](배치, executemany). 식별자는 자동 quoting, 값은 파라미터 바인딩.
|
|
303
|
+
postgres.upsert(
|
|
304
|
+
'enrichment.product_detail_records',
|
|
305
|
+
{"mall_product_no": 123, "status": "ok", "updated_at": None},
|
|
306
|
+
conflict_keys=['mall_product_no'], # 복합키도 가능: ['a','b','c','d']
|
|
307
|
+
update_columns=None, # None이면 conflict_keys/auto_now 제외 전체
|
|
308
|
+
auto_now=['updated_at'], # NOW()로 채움(INSERT/UPDATE 양쪽)
|
|
309
|
+
) # 반환: 영향 rowcount
|
|
310
|
+
|
|
311
|
+
# UPDATE
|
|
312
|
+
postgres.update('QUERY_STRING', params=None)
|
|
313
|
+
|
|
314
|
+
# DELETE
|
|
315
|
+
postgres.delete('QUERY_STRING', params=None)
|
|
316
|
+
|
|
317
|
+
# show Databases
|
|
318
|
+
postgres.databases()
|
|
319
|
+
|
|
320
|
+
# show Tables
|
|
321
|
+
postgres.tables()
|
|
322
|
+
|
|
323
|
+
# Current schema
|
|
324
|
+
postgres.current_schema()
|
|
325
|
+
|
|
326
|
+
# Ping
|
|
327
|
+
postgres.ping()
|
|
328
|
+
|
|
329
|
+
# Close
|
|
330
|
+
postgres.close()
|
|
331
|
+
|
|
332
|
+
# debug query : default True
|
|
333
|
+
postgres.query_debug(False)
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### MongoDB (Deprecated)
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
> ⚠️ Deprecated since v2.2.0, removal in v3.0.0. Requires `pip install echoss-db[mongo]`.
|
|
341
|
+
|
|
342
|
+
```python
|
|
343
|
+
# show Database
|
|
344
|
+
mongo.databases()
|
|
345
|
+
|
|
346
|
+
# show Collections
|
|
347
|
+
mongo.collections()
|
|
348
|
+
|
|
349
|
+
# Ping
|
|
350
|
+
mongo.ping()
|
|
351
|
+
|
|
352
|
+
# SELECT
|
|
353
|
+
mongo.select('COLLECTION_NAME','QUERY_STRING or DICTIONARY')
|
|
354
|
+
|
|
355
|
+
# INSERT
|
|
356
|
+
mongo.insert('COLLECTION_NAME','QUERY_STRING or DICTIONARY')
|
|
357
|
+
mongo.insert_many('COLLECTION_NAME','QUERY_STRING or DICTIONARY')
|
|
358
|
+
|
|
359
|
+
# UPDATE
|
|
360
|
+
mongo.update('COLLECTION_NAME','FILTER_STRING or DICTIONARY', 'UPDATE_STRING or DICTIONARY')
|
|
361
|
+
mongo.update_many('COLLECTION_NAME','FILTER_STRING or DICTIONARY', 'UPDATE_STRING or DICTIONARY')
|
|
362
|
+
|
|
363
|
+
# DELETE
|
|
364
|
+
mongo.delete('COLLECTION_NAME','QUERY_STRING or DICTIONARY')
|
|
365
|
+
mongo.delete_many('COLLECTION_NAME','QUERY_STRING or DICTIONARY')
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### ElasticSearch
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
```python
|
|
373
|
+
# CREATE
|
|
374
|
+
elastic.index(index='INDEX_NAME')
|
|
375
|
+
|
|
376
|
+
# DROP
|
|
377
|
+
elastic.delete_index(index='INDEX_NAME')
|
|
378
|
+
|
|
379
|
+
# SELECT
|
|
380
|
+
elastic.search(body=query)
|
|
381
|
+
elastic.search_list(body=query, fetch_all=True)
|
|
382
|
+
elastic.search_dataframe(body=query, fetch_all=True)
|
|
383
|
+
elastic.search_field(field='FIELD_NAME',value='VALUE')
|
|
384
|
+
|
|
385
|
+
# INSERT
|
|
386
|
+
elastic.index(index='INDEX_NAME', body='JSON_BODY', id='ID')
|
|
387
|
+
|
|
388
|
+
# UPDATE
|
|
389
|
+
elastic.update(id='ID', body='JSON_BODY')
|
|
390
|
+
|
|
391
|
+
# DELETE
|
|
392
|
+
elastic.delete(id='ID')
|
|
393
|
+
|
|
394
|
+
# SCROLL
|
|
395
|
+
elastic.prepare_scroll(
|
|
396
|
+
index_name='farmers_index',
|
|
397
|
+
query={'match_all': {}},
|
|
398
|
+
source_fields=['name', 'code'],
|
|
399
|
+
size=10000,
|
|
400
|
+
scroll_ttl='2m'
|
|
401
|
+
)
|
|
402
|
+
chunk_list = elastic.next_scroll_chunk()
|
|
403
|
+
|
|
404
|
+
# BULK
|
|
405
|
+
success, error_list = elastic.bulk_insert('farm_index', doc_list, id_field='farm_id')
|
|
406
|
+
success, error_list = elastic.bulk_upsert('farm_index', doc_list, id_field='farm_id')
|
|
407
|
+
|
|
408
|
+
# Ping
|
|
409
|
+
elastic.ping()
|
|
410
|
+
|
|
411
|
+
# Connection Information
|
|
412
|
+
elastic.info()
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Qdrant
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
`QdrantVector`는 기본적으로 FastEmbed 모델을 사용합니다.
|
|
420
|
+
기본 설치는 `qdrant-client[fastembed]`를 포함하며, Python 3.11+ 환경을 전제로 합니다.
|
|
421
|
+
|
|
422
|
+
Manual test 실행 순서:
|
|
423
|
+
1. `tests/manual/example_postgres_qdrant_ingest.py` (테스트용 충분한 chunk 데이터 생성)
|
|
424
|
+
2. `tests/manual/example_qdrant.py` (Qdrant 업서트/검색 확인)
|
|
425
|
+
|
|
426
|
+
1. `fastembed_model` 미설정
|
|
427
|
+
- 기본값 `sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2`(384차원)가 자동 적용됩니다.
|
|
428
|
+
- 이때 **초기화 시 경고 로그**가 출력됩니다. 외부에서 계산한 벡터(예: 1024차원)를 직접 넣으려면 `fastembed_model: null`로 설정해야 하며, 미설정 상태로 `upsert_vectors()`를 호출하면 차원 불일치 오류가 납니다.
|
|
429
|
+
- 설치/runtime 문제가 있으면 fallback 없이 초기화 단계에서 예외가 발생합니다.
|
|
430
|
+
- 모델 상세(설명 포함) 목록: `list_supported_models_by_class("TextEmbedding")`
|
|
431
|
+
- `vector` 입력 없이 원문 텍스트(`document`/`text`/`content`)를 전달합니다.
|
|
432
|
+
- 명시 메서드 `upsert_texts()` / `search_text()` 사용을 권장합니다.
|
|
433
|
+
- `create_collection()`의 차원은 모델에서 자동 추론합니다.
|
|
434
|
+
|
|
435
|
+
2. `fastembed_model` 설정
|
|
436
|
+
- 지정한 모델로 동작합니다.
|
|
437
|
+
- `create_collection()`의 차원은 설정 모델 기준으로 자동 추론합니다.
|
|
438
|
+
|
|
439
|
+
3. `fastembed_model: null`
|
|
440
|
+
- FastEmbed를 명시적으로 비활성화하고 벡터 직접 주입 모드로 동작합니다.
|
|
441
|
+
- 이 경우 `upsert_vectors()` / `search_vector()` 사용을 권장합니다.
|
|
442
|
+
- `create_collection(dim=...)`에서 `dim`은 필수입니다.
|
|
443
|
+
|
|
444
|
+
Config example:
|
|
445
|
+
|
|
446
|
+
```yaml
|
|
447
|
+
qdrant:
|
|
448
|
+
host: <QDRANT_HOST>
|
|
449
|
+
port: <QDRANT_PORT>
|
|
450
|
+
scheme: <http|https>
|
|
451
|
+
collection: <QDRANT_COLLECTION>
|
|
452
|
+
timeout: <SECONDS>
|
|
453
|
+
default_limit: <DEFAULT_LIMIT>
|
|
454
|
+
fastembed_model: sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
Text-input upsert example (`fastembed_model` enabled):
|
|
458
|
+
|
|
459
|
+
```python
|
|
460
|
+
points = [
|
|
461
|
+
{"id": 1, "document": "RAG 시스템 설계 문서", "payload": {"source": "wiki"}},
|
|
462
|
+
{"id": 2, "text": "Qdrant 검색 예제", "payload": {"source": "blog"}},
|
|
463
|
+
]
|
|
464
|
+
qdrant.upsert_texts(points, collection='ai_rag_chunks')
|
|
465
|
+
|
|
466
|
+
hits = qdrant.search_text(query_text='RAG 아키텍처', limit=5, collection='ai_rag_chunks')
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
External vector-input mode is documented as a code pattern only (for lightweight tutorial runtime):
|
|
470
|
+
|
|
471
|
+
```python
|
|
472
|
+
qdrant = QdrantVector({
|
|
473
|
+
'qdrant': {
|
|
474
|
+
'host': '<host>',
|
|
475
|
+
'port': 6333,
|
|
476
|
+
'scheme': 'http',
|
|
477
|
+
'collection': 'ai_rag_chunks_external',
|
|
478
|
+
'fastembed_model': None,
|
|
479
|
+
}
|
|
480
|
+
})
|
|
481
|
+
|
|
482
|
+
points = [{"id": 1, "vector": your_embed_fn("문서"), "payload": {"source": "external"}}]
|
|
483
|
+
qdrant.create_collection(dim=len(points[0]['vector']))
|
|
484
|
+
qdrant.upsert_vectors(points)
|
|
485
|
+
hits = qdrant.search_vector(vector=your_embed_fn('질의'))
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
Payload filter on search (외부 벡터 + 조건 검색):
|
|
489
|
+
|
|
490
|
+
```python
|
|
491
|
+
# dict 필터: 값이 list면 MatchAny, scalar면 MatchValue로 자동 변환
|
|
492
|
+
hits = qdrant.search_vector(
|
|
493
|
+
vector=your_embed_fn('질의'),
|
|
494
|
+
filter_={"doc_type": ["summary_long", "faq_question"], # MatchAny
|
|
495
|
+
"mall_product_no": 123}, # MatchValue
|
|
496
|
+
limit=10,
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
# 고급 조건은 qdrant_client Filter 객체를 그대로 전달 (should/must_not/range 등)
|
|
500
|
+
import qdrant_client.http.models as qm
|
|
501
|
+
hits = qdrant.search_vector(vector=v, filter_=qm.Filter(must_not=[...]))
|
|
502
|
+
|
|
503
|
+
# 빌더만 단독 사용도 가능
|
|
504
|
+
qfilter = qdrant.build_filter({"doc_type": ["faq_question"]})
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
> 주의: 구버전(1.2.x)은 `access_tags_any` 외의 dict 키를 **무시**했습니다. 2.2.0부터 일반 dict 키가 실제 필터로 적용되므로, 기존에 무시되던 dict를 넘기던 호출은 결과가 달라질 수 있습니다(의도된 동작 변경).
|
|
508
|
+
|
|
509
|
+
Collection metadata / management:
|
|
510
|
+
|
|
511
|
+
```python
|
|
512
|
+
info = qdrant.get_collection_info('ai_rag_chunks')
|
|
513
|
+
# {"name": ..., "vectors": {"default": {"size": 1024, "distance": "Cosine"}},
|
|
514
|
+
# "points_count": 3300, "status": "green"}
|
|
515
|
+
|
|
516
|
+
# 차원 불일치 시 재생성 마이그레이션을 wrapper 안에서 완결
|
|
517
|
+
if info["vectors"]["default"]["size"] != 1024:
|
|
518
|
+
qdrant.delete_collection('ai_rag_chunks')
|
|
519
|
+
qdrant.create_collection(dim=1024, collection='ai_rag_chunks')
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
Large-dimension upsert robustness (retry / batching):
|
|
523
|
+
|
|
524
|
+
```python
|
|
525
|
+
# 대형 차원(예: 1024d) 대량 적재 시 timeout 권장값: 30초 이상
|
|
526
|
+
# (config의 qdrant.timeout). 실패에 대비해 retry/backoff, 대량은 batch_size 사용.
|
|
527
|
+
qdrant.upsert_vectors(
|
|
528
|
+
points, # 수천 건
|
|
529
|
+
retry=3, backoff=0.5, # 실패 시 0.5, 1.0, 2.0초 백오프로 재시도
|
|
530
|
+
batch_size=256, # 256개씩 청크 전송
|
|
531
|
+
wait=True,
|
|
532
|
+
)
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
### Mapping Lite (Optional)
|
|
536
|
+
|
|
537
|
+
---
|
|
538
|
+
|
|
539
|
+
`echoss_db.mapping`은 ORM이 아닌 경량 row/model 매핑 기능입니다.
|
|
540
|
+
|
|
541
|
+
```python
|
|
542
|
+
from dataclasses import dataclass
|
|
543
|
+
from echoss_db.mapping import map_row, map_rows, to_params
|
|
544
|
+
|
|
545
|
+
@dataclass
|
|
546
|
+
class UserDTO:
|
|
547
|
+
id: int
|
|
548
|
+
name: str
|
|
549
|
+
age: int = 0
|
|
550
|
+
|
|
551
|
+
row = {"id": 1, "name": "kim"}
|
|
552
|
+
dto = map_row(row, UserDTO)
|
|
553
|
+
dto_list = map_rows([row], UserDTO)
|
|
554
|
+
params = to_params(dto)
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
- 기본 설치: dataclass 지원
|
|
558
|
+
- 선택 설치(`echoss-db[mapping]`): pydantic 모델 지원
|
|
559
|
+
- 튜토리얼: `tests/manual/example_mapping_mysql.py`
|
|
560
|
+
|
|
561
|
+
### Code Quality
|
|
562
|
+
|
|
563
|
+
When creating new functions, please follow the Google style Python docstrings. See example below:
|
|
564
|
+
|
|
565
|
+
```python
|
|
566
|
+
def example_function(param1: int, param2: str) -> bool:
|
|
567
|
+
"""Example function that does something.
|
|
568
|
+
|
|
569
|
+
Args:
|
|
570
|
+
param1: The first parameter.
|
|
571
|
+
param2: The second parameter.
|
|
572
|
+
|
|
573
|
+
Returns:
|
|
574
|
+
The return value. True for success, False otherwise.
|
|
575
|
+
|
|
576
|
+
"""
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
## Version history
|
|
580
|
+
|
|
581
|
+
v0.1.0 initial version
|
|
582
|
+
v0.1.1 echoss_logger include
|
|
583
|
+
v0.1.7 mysql support query with params. return cursor.rowcount for insert/update/delete query
|
|
584
|
+
v1.0.0 mysql support query with list params
|
|
585
|
+
v1.0.1 elastic search_list fetch_all option, mongo support insert_many, delete_many, update_many method
|
|
586
|
+
v1.0.2 mysql reuse cursor
|
|
587
|
+
v1.0.7 echoss-query last version
|
|
588
|
+
v1.0.8 change package name to echoss-db
|
|
589
|
+
v1.0.11 update() check 'doc' or 'script' in body
|
|
590
|
+
v1.1.0 add Scroll, Bulk functions in ElasticSearch
|
|
591
|
+
v1.1.5 improve prepare_scroll and dataframe conversion logic, add request_timeout in bulk operation
|
|
592
|
+
v1.2.0 change mysql base package to sqlalchemy (previous version use pymysql)
|
|
593
|
+
v1.2.1 add return_lastrowid parameter in insert() method
|
|
594
|
+
v1.2.2 return dictionary select result
|
|
595
|
+
v1.2.3 add postgres DB and qdrant vector storage support
|
|
596
|
+
v2.0.0 add optional `echoss_db.mapping` (dataclass default, pydantic optional)
|
|
597
|
+
v2.1.0 raise Python baseline to 3.11, standardize on psycopg3, and keep Qdrant fastembed as default runtime
|
|
598
|
+
v2.2.0 qdrant generalized dict filter (breaking behavior: previously ignored keys now applied) and get_collection_info, postgres upsert/parse_json options, upsert retry/backoff/batch_size, deprecate MongoQuery (pymongo moved to optional extra [mongo]), raise Python floor to 3.12
|