-
Notifications
You must be signed in to change notification settings - Fork 165
Expand file tree
/
Copy pathparent_chunk_store.py
More file actions
131 lines (114 loc) · 4.76 KB
/
Copy pathparent_chunk_store.py
File metadata and controls
131 lines (114 loc) · 4.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
"""父级分块文档存储(用于 Auto-merging Retriever)"""
from datetime import datetime
from typing import List
from backend.infra.cache import cache
from backend.infra.database import SessionLocal
from backend.db.models import ParentChunk
class ParentChunkStore:
"""基于 PostgreSQL + Redis 的父级分块存储。"""
@staticmethod
def _to_dict(item: ParentChunk) -> dict:
return {
"text": item.text,
"filename": item.filename,
"file_type": item.file_type,
"file_path": item.file_path,
"page_number": item.page_number,
"chunk_id": item.chunk_id,
"parent_chunk_id": item.parent_chunk_id,
"root_chunk_id": item.root_chunk_id,
"chunk_level": item.chunk_level,
"chunk_idx": item.chunk_idx,
}
@staticmethod
def _cache_key(chunk_id: str) -> str:
return f"parent_chunk:{chunk_id}"
def upsert_documents(self, docs: List[dict]) -> int:
"""写入/更新父级分块,返回写入条数。"""
if not docs:
return 0
db = SessionLocal()
upserted = 0
try:
for doc in docs:
chunk_id = (doc.get("chunk_id") or "").strip()
if not chunk_id:
continue
record = db.query(ParentChunk).filter(ParentChunk.chunk_id == chunk_id).first()
payload = {
"text": doc.get("text", ""),
"filename": doc.get("filename", ""),
"file_type": doc.get("file_type", ""),
"file_path": doc.get("file_path", ""),
"page_number": int(doc.get("page_number", 0) or 0),
"parent_chunk_id": doc.get("parent_chunk_id", ""),
"root_chunk_id": doc.get("root_chunk_id", ""),
"chunk_level": int(doc.get("chunk_level", 0) or 0),
"chunk_idx": int(doc.get("chunk_idx", 0) or 0),
"updated_at": datetime.utcnow(),
}
cache_payload = {
"chunk_id": chunk_id,
"text": payload["text"],
"filename": payload["filename"],
"file_type": payload["file_type"],
"file_path": payload["file_path"],
"page_number": payload["page_number"],
"parent_chunk_id": payload["parent_chunk_id"],
"root_chunk_id": payload["root_chunk_id"],
"chunk_level": payload["chunk_level"],
"chunk_idx": payload["chunk_idx"],
}
if record:
for key, value in payload.items():
setattr(record, key, value)
else:
db.add(ParentChunk(chunk_id=chunk_id, **payload))
cache.set_json(self._cache_key(chunk_id), cache_payload)
upserted += 1
db.commit()
finally:
db.close()
return upserted
def get_documents_by_ids(self, chunk_ids: List[str]) -> List[dict]:
if not chunk_ids:
return []
ordered_results = {}
missing_ids = []
for chunk_id in chunk_ids:
key = (chunk_id or "").strip()
if not key:
continue
cached = cache.get_json(self._cache_key(key))
if cached:
ordered_results[key] = cached
else:
missing_ids.append(key)
if missing_ids:
db = SessionLocal()
try:
rows = db.query(ParentChunk).filter(ParentChunk.chunk_id.in_(missing_ids)).all()
for row in rows:
payload = self._to_dict(row)
ordered_results[row.chunk_id] = payload
cache.set_json(self._cache_key(row.chunk_id), payload)
finally:
db.close()
return [ordered_results[item] for item in chunk_ids if item in ordered_results]
def delete_by_filename(self, filename: str) -> int:
"""按文件名删除父级分块,返回删除条数。"""
if not filename:
return 0
db = SessionLocal()
try:
rows = db.query(ParentChunk).filter(ParentChunk.filename == filename).all()
chunk_ids = [row.chunk_id for row in rows]
deleted = len(chunk_ids)
if deleted > 0:
db.query(ParentChunk).filter(ParentChunk.filename == filename).delete(synchronize_session=False)
db.commit()
for chunk_id in chunk_ids:
cache.delete(self._cache_key(chunk_id))
return deleted
finally:
db.close()