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.
Files changed (55) hide show
  1. {echoss_db-1.2.4 → echoss_db-2.2.1}/MANIFEST.in +3 -3
  2. echoss_db-2.2.1/PKG-INFO +598 -0
  3. echoss_db-2.2.1/README.md +567 -0
  4. {echoss_db-1.2.4 → echoss_db-2.2.1}/echoss_db/elastic_search.py +7 -1
  5. echoss_db-2.2.1/echoss_db/mapping/__init__.py +11 -0
  6. echoss_db-2.2.1/echoss_db/mapping/dataclass_mapper.py +35 -0
  7. echoss_db-2.2.1/echoss_db/mapping/errors.py +6 -0
  8. echoss_db-2.2.1/echoss_db/mapping/param_mapper.py +28 -0
  9. echoss_db-2.2.1/echoss_db/mapping/pydantic_mapper.py +43 -0
  10. echoss_db-2.2.1/echoss_db/mapping/row_mapper.py +34 -0
  11. echoss_db-2.2.1/echoss_db/mapping/types.py +4 -0
  12. {echoss_db-1.2.4 → echoss_db-2.2.1}/echoss_db/mongo_query.py +24 -0
  13. {echoss_db-1.2.4 → echoss_db-2.2.1}/echoss_db/mysql_query.py +15 -1
  14. {echoss_db-1.2.4 → echoss_db-2.2.1}/echoss_db/postgres_query.py +201 -7
  15. {echoss_db-1.2.4 → echoss_db-2.2.1}/echoss_db/qdrant_vector.py +168 -31
  16. echoss_db-2.2.1/echoss_db/sql_transaction.py +169 -0
  17. echoss_db-2.2.1/echoss_db.egg-info/PKG-INFO +598 -0
  18. echoss_db-2.2.1/echoss_db.egg-info/SOURCES.txt +46 -0
  19. echoss_db-2.2.1/echoss_db.egg-info/requires.txt +18 -0
  20. echoss_db-2.2.1/echoss_db.egg-info/top_level.txt +4 -0
  21. echoss_db-2.2.1/pyproject.toml +46 -0
  22. {echoss_db-1.2.4 → echoss_db-2.2.1}/requirements.txt +2 -3
  23. echoss_db-2.2.1/tests/__init__.py +0 -0
  24. echoss_db-2.2.1/tests/integration/__init__.py +0 -0
  25. echoss_db-2.2.1/tests/integration/conftest.py +65 -0
  26. echoss_db-2.2.1/tests/integration/test_postgres_integration.py +98 -0
  27. echoss_db-2.2.1/tests/integration/test_qdrant_integration.py +66 -0
  28. echoss_db-2.2.1/tests/manual/__init__.py +0 -0
  29. echoss_db-2.2.1/tests/manual/_postgres_test_schema.py +14 -0
  30. {echoss_db-1.2.4/tutorial → echoss_db-2.2.1/tests/manual}/example_elasticsearch.py +3 -2
  31. echoss_db-2.2.1/tests/manual/example_mapping_mysql.py +91 -0
  32. {echoss_db-1.2.4/tutorial → echoss_db-2.2.1/tests/manual}/example_mongo.py +2 -4
  33. {echoss_db-1.2.4/tutorial → echoss_db-2.2.1/tests/manual}/example_mysql.py +2 -2
  34. {echoss_db-1.2.4/tutorial → echoss_db-2.2.1/tests/manual}/example_postgres.py +8 -3
  35. {echoss_db-1.2.4/tutorial → echoss_db-2.2.1/tests/manual}/example_postgres_qdrant_ingest.py +9 -4
  36. {echoss_db-1.2.4/tutorial → echoss_db-2.2.1/tests/manual}/example_qdrant.py +9 -3
  37. echoss_db-2.2.1/tests/manual/setup_ai_rag_test_schema.sql +34 -0
  38. echoss_db-2.2.1/tests/unit/__init__.py +0 -0
  39. echoss_db-2.2.1/tests/unit/mapping/__init__.py +1 -0
  40. echoss_db-2.2.1/tests/unit/mapping/test_param_mapper.py +48 -0
  41. echoss_db-1.2.4/PKG-INFO +0 -334
  42. echoss_db-1.2.4/README.md +0 -301
  43. echoss_db-1.2.4/echoss_db.egg-info/PKG-INFO +0 -334
  44. echoss_db-1.2.4/echoss_db.egg-info/SOURCES.txt +0 -26
  45. echoss_db-1.2.4/echoss_db.egg-info/requires.txt +0 -8
  46. echoss_db-1.2.4/echoss_db.egg-info/top_level.txt +0 -1
  47. echoss_db-1.2.4/setup.py +0 -33
  48. {echoss_db-1.2.4 → echoss_db-2.2.1}/LICENSE +0 -0
  49. {echoss_db-1.2.4 → echoss_db-2.2.1}/echoss_db/__init__.py +0 -0
  50. {echoss_db-1.2.4 → echoss_db-2.2.1}/echoss_db.egg-info/dependency_links.txt +0 -0
  51. {echoss_db-1.2.4 → echoss_db-2.2.1}/package_tests/test_package_imports.py +0 -0
  52. {echoss_db-1.2.4 → echoss_db-2.2.1}/setup.cfg +0 -0
  53. {echoss_db-1.2.4/tutorial → echoss_db-2.2.1/tests/manual}/example_elasticsearch.ipynb +0 -0
  54. {echoss_db-1.2.4/tutorial → echoss_db-2.2.1/tests/manual}/example_mongo.ipynb +0 -0
  55. {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
- recursive-include tutorial *.py *.ipynb
5
+ prune _archive
6
+ recursive-include tests *.py *.ipynb *.sql
6
7
  recursive-include package_tests *.py
7
- recursive-exclude tutorial .ipynb_checkpoints/*
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~
@@ -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