Skip to content

Commit fb26d0b

Browse files
author
MrCabss69
committed
Fixed implementation - now shoud be simplier
1 parent e029ba8 commit fb26d0b

2 files changed

Lines changed: 128 additions & 101 deletions

File tree

rre-dataset-generator/src/search_engine/data_store.py

Lines changed: 65 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
configure_logging(level=logging.INFO)
1313
log = logging.getLogger(__name__)
1414

15+
16+
TMP_FILE = "./test_file.json"
17+
1518
class DataStore:
1619
"""
1720
Stores/retrieves documents, queries, and rating scores.
@@ -117,72 +120,75 @@ def has_rating_score(self, query_id: str, doc_id: str) -> bool:
117120
return context.has_rating_score(doc_id)
118121

119122

120-
def save_queries_and_docs(self, filepath: str | Path) -> None:
121-
"""
122-
Saves all query contexts (query_id, text, doc_ids) to a JSON file.
123-
"""
124-
data = [
125-
{
126-
"query_id": ctx.get_query_id(),
127-
"query_text": ctx.get_query(),
128-
"doc_ids": ctx.get_doc_ids()
129-
}
130-
for ctx in self._queries_by_id.values()
131-
]
123+
@staticmethod
124+
def query_context_docs_to_dict(query: QueryRatingContext, documents: List[Document]) -> dict:
125+
return {
126+
"query_id": query.get_query_id(),
127+
"query_text": query.get_query(),
128+
"doc_ids": query.get_doc_ids(),
129+
"doc_ratings": query._doc_id_to_rating_score.copy(), # copy to avoid mutation
130+
"documents": [doc.model_dump_json() for doc in documents if doc is not None]
131+
}
132+
133+
@staticmethod
134+
def dict_to_query_context_docs(dict_: dict) -> tuple[str, str, list[str], dict[str, int], list[dict]]:
135+
query_id = dict_["query_id"]
136+
query_text = dict_["query_text"]
137+
doc_ids = dict_["doc_ids"]
138+
doc_ratings = dict_["doc_ratings"]
139+
documents = dict_.get("documents", [])
140+
return query_id, query_text, doc_ids, doc_ratings, documents
141+
142+
143+
def save_tmp_file_content(self, filepath: str | Path = None) -> None:
144+
"""
145+
Save _queries_by_id, _query_text_to_query_id, and self._documents from a unified JSON file in disk
146+
"""
147+
global TMP_FILE
148+
if filepath is None:
149+
filepath = TMP_FILE
150+
151+
all_content = []
152+
for query_ctx in self._queries_by_id.values():
153+
docs_ = [self.get_document(doc_id) for doc_id in query_ctx.get_doc_ids()]
154+
data = self.query_context_docs_to_dict(query_ctx, docs_)
155+
all_content.append(data)
156+
132157
with open(filepath, "w", encoding="utf-8") as f:
133-
json.dump(data, f, indent=2)
158+
json.dump(all_content, f, indent=2)
134159

135160

136-
def load_queries_and_docs(self, filepath: str | Path) -> None:
161+
162+
def load_tmp_file_content(self, filepath: str | Path = None) -> None:
137163
"""
138-
Loads query contexts from a JSON file. Reconstructs query_id, query text, and associated doc_ids.
164+
Reconstruct _queries_by_id, _query_text_to_query_id, and self._documents from disk file
139165
"""
140-
with open(filepath, "r", encoding="utf-8") as f:
141-
data = json.load(f)
142-
143-
for item in data:
144-
context = QueryRatingContext(item["query_text"], doc_id=None)
145-
context._id = item["query_id"]
146-
for doc_id in item["doc_ids"]:
147-
context.add_doc_id(doc_id)
148-
self._queries_by_id[context.get_query_id()] = context
149-
self._query_text_to_query_id[context.get_query()] = context.get_query_id()
150-
151-
152-
def save_rating_triples(self, filepath: str | Path) -> None:
153-
"""
154-
Saves all (query_id, doc_id, score) triples to a JSON file.
155-
"""
156-
triples = []
157-
for _context in self._queries_by_id.values():
158-
query_id = _context.get_query_id()
159-
for doc_id in _context.get_doc_ids():
160-
try:
161-
score = _context.get_rating_score(doc_id)
162-
triples.append({
163-
"query_id": query_id,
164-
"doc_id": doc_id,
165-
"score": score
166-
})
167-
except KeyError:
168-
continue
169-
with open(filepath, "w", encoding="utf-8") as f:
170-
json.dump(triples, f, indent=2)
166+
global TMP_FILE
171167

168+
if filepath is None:
169+
filepath = TMP_FILE
172170

173-
def load_rating_triples(self, filepath: str | Path) -> None:
174-
"""
175-
Loads rating triples from a JSON file and updates existing QueryRatingContext entries.
176-
"""
177171
with open(filepath, "r", encoding="utf-8") as f:
178-
triples = json.load(f)
179-
180-
for triple in triples:
181-
query_id = triple["query_id"]
182-
doc_id = triple["doc_id"]
183-
score = triple["score"]
184-
if query_id not in self._queries_by_id:
185-
raise ValueError(f"Query ID {query_id} not found when loading triples.")
186-
self._queries_by_id[query_id].add_rating_score(doc_id, score)
172+
all_content = json.load(f)
173+
174+
# Loop to reconstruct each register
175+
for entry in all_content:
176+
query_id, query_text, doc_ids, doc_ratings, documents = self.dict_to_query_context_docs(entry)
177+
178+
# Register docs
179+
for doc_data in documents:
180+
document = Document.model_validate(doc_data)
181+
self.add_document(document.id, document)
182+
183+
# Reconstruct the QueryRating
184+
context = QueryRatingContext(query=query_text)
185+
context._id = query_id # generated UUID
186+
187+
for doc_id in doc_ids:
188+
context.add_doc_id(doc_id)
187189

190+
for doc_id, rating in doc_ratings.items():
191+
context.add_rating_score(doc_id, rating)
188192

193+
self._queries_by_id[query_id] = context
194+
self._query_text_to_query_id[query_text] = query_id

rre-dataset-generator/tests/unit/test_data_store.py

Lines changed: 63 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -61,48 +61,69 @@ def test_add_and_get_query_expect_query_stored_in_data_store_and_check_same_quer
6161

6262

6363
# tmp_path: pytest fixture with a temporal dir
64-
def test_save_and_load_queries_and_ratings_roundtrip(tmp_path):
64+
def test_save_tmp_file_content_expect_json_created(tmp_path):
65+
ds = DataStore()
6566

66-
# Step 1: build the intial instance
67-
ds1 = DataStore()
68-
69-
# Step 2: add Documents
67+
# Add Documents
7068
doc1 = Document(id="d1", fields={"title": "AI", "text": "Deep learning"})
7169
doc2 = Document(id="d2", fields={"title": "LLMs", "text": "Transformers"})
72-
ds1.add_document(doc1.id, doc1)
73-
ds1.add_document(doc2.id, doc2)
74-
75-
# Step 3: add queries and ratings
76-
qid1 = ds1.add_query("artificial intelligence", doc1.id)
77-
ds1.add_rating_score(qid1, doc1.id, 1)
78-
ds1.add_rating_score(qid1, doc2.id, 0)
79-
80-
qid2 = ds1.add_query("transformer models", doc2.id)
81-
ds1.add_rating_score(qid2, doc2.id, 1)
82-
83-
# Step 4: save into disk
84-
queries_path = tmp_path / "queries.json"
85-
triples_path = tmp_path / "triples.json"
86-
87-
ds1.save_queries_and_docs(queries_path)
88-
ds1.save_rating_triples(triples_path)
89-
90-
# Step 5: Verify saving
91-
assert queries_path.exists()
92-
assert triples_path.exists()
93-
assert json.loads(queries_path.read_text(encoding="utf-8")) # assert not empty
94-
assert json.loads(triples_path.read_text(encoding="utf-8")) # assert not empty
95-
96-
# Step 6: load a new datastore - avoid caching artifacts
97-
ds2 = DataStore()
98-
ds2.load_queries_and_docs(queries_path)
99-
ds2.load_rating_triples(triples_path)
100-
101-
# Step 7: verify integrity after loading
102-
assert ds2.get_query(qid1).get_query() == "artificial intelligence"
103-
assert set(ds2.get_query(qid1).get_doc_ids()) == {"d1", "d2"}
104-
assert ds2.get_rating_score(qid1, "d1") == 1
105-
assert ds2.get_rating_score(qid1, "d2") == 0
106-
107-
assert ds2.get_query(qid2).get_query() == "transformer models"
108-
assert ds2.get_rating_score(qid2, "d2") == 1
70+
ds.add_document(doc1.id, doc1)
71+
ds.add_document(doc2.id, doc2)
72+
73+
# Add Queries and Ratings
74+
qid1 = ds.add_query("artificial intelligence", doc1.id)
75+
ds.add_rating_score(qid1, "d1", 1)
76+
ds.add_rating_score(qid1, "d2", 0)
77+
78+
qid2 = ds.add_query("transformer models", doc2.id)
79+
ds.add_rating_score(qid2, "d2", 1)
80+
81+
# Save to disk
82+
path = tmp_path / "datastore.json"
83+
ds.save_tmp_file_content(path)
84+
85+
# Assertions
86+
assert path.exists()
87+
data = json.loads(path.read_text(encoding="utf-8"))
88+
assert isinstance(data, list)
89+
assert len(data) == 2
90+
for entry in data:
91+
assert "query_id" in entry
92+
assert "query_text" in entry
93+
assert "doc_ids" in entry
94+
assert "doc_ratings" in entry
95+
assert "documents" in entry
96+
97+
98+
def test_load_tmp_file_content_expect_data_restored_correctly(tmp_path):
99+
# Create known content
100+
content = [
101+
{
102+
"query_id": "q1",
103+
"query_text": "ai",
104+
"doc_ids": ["d1", "d2"],
105+
"doc_ratings": {"d1": 1, "d2": 0},
106+
"documents": [
107+
{"id": "d1", "fields": {"title": "AI", "text": "Deep learning"}},
108+
{"id": "d2", "fields": {"title": "LLMs", "text": "Transformers"}},
109+
]
110+
}
111+
]
112+
113+
# Write file manually
114+
path = tmp_path / "datastore.json"
115+
path.write_text(json.dumps(content, indent=2), encoding="utf-8")
116+
117+
# Load from disk
118+
ds = DataStore()
119+
ds.load_tmp_file_content(path)
120+
121+
# Assertions
122+
assert ds.get_query("q1").get_query() == "ai"
123+
assert ds.get_rating_score("q1", "d1") == 1
124+
assert ds.get_rating_score("q1", "d2") == 0
125+
126+
doc1 = ds.get_document("d1")
127+
doc2 = ds.get_document("d2")
128+
assert doc1.fields["title"] == "AI"
129+
assert doc2.fields["text"] == "Transformers"

0 commit comments

Comments
 (0)