forked from alexysxeightn/MADE
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtask_inverted_index_cli.py
More file actions
176 lines (141 loc) · 5.49 KB
/
Copy pathtask_inverted_index_cli.py
File metadata and controls
176 lines (141 loc) · 5.49 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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
"""
Library provides CLI to work with inverted index
use load_documents to load document to build inverted index
use build_inverted_index to build inverted index for provided documents
"""
from __future__ import annotations
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
from typing import Dict, List
from collections import defaultdict
import re
import pickle
import json
class InvertedIndex:
"""
Class can dump, load inverted index and take answer to query
use InvertedIndex.query to get result of query
use InvertedIndex.dump to upload inverted index to disk
use InvertedIndex.load to load inverted index from disk
"""
def __init__(self, documents: Dict[str, List[int]]):
self._data = documents
def __eq__(self, other: InvertedIndex):
if self._data is None or other._data is None:
return False
self_inverted_index = {k: sorted(v) for k, v in self._data.items()}
other_inverted_index = {k: sorted(v) for k, v in other._data.items()}
return self_inverted_index == other_inverted_index
def query(self, words: List[str]) -> List[int]:
"""
Return the list of relevant documents for the given query
function converts all words to lowercase and return
list of documents ids that contain all this words
"""
words = [word.lower() for word in words]
if words[0] not in self._data.keys():
return []
answer = set(self._data[words[0]])
for word in words:
if word not in self._data.keys():
return []
answer = answer & set(self._data[word])
return list(answer)
def dump(self, filepath: str, dump_method: str) -> None:
"""
Dump the Inverted Index into the given path
function can dump inverted index using pickle or json
dump_method is 'pickle' or 'json'
pickle dump in binary file, json dump in ordinary file
"""
if dump_method == "pickle":
with open(filepath, 'wb') as file:
pickle.dump(self._data, file)
elif dump_method == "json":
with open(filepath, 'w') as file:
json.dump(self._data, file)
@classmethod
def load(cls, filepath: str) -> InvertedIndex:
"""Load the Inverted Index from given path (so far only json)"""
with open(filepath, 'r') as file:
docs = json.load(file)
return cls(documents=docs)
def load_documents(filepath: str) -> Dict[int, str]:
"""
Function load dataset from filepath
function create dict, where key is document id and item is
document without tab and in lowercase
"""
documents = dict()
with open(filepath) as file:
file_content = file.readlines()
for line in file_content:
doc_id, content = line.lower().split("\t", 1)
doc_id = int(doc_id)
documents[doc_id] = content.strip()
return documents
def build_inverted_index(documents: Dict[int, str]) -> InvertedIndex:
"""Function return InvertedIndex object, which build on documents"""
inverted_index = defaultdict(list)
for key in documents.keys():
for word in set(re.split(r"\W+", documents[key])):
inverted_index[word].append(key)
return InvertedIndex(inverted_index)
def callback_build(arguments):
"""Function for command 'build' is CLI
function create inverted index on dataset and dump it in output
dump_method = strategy
"""
documents = load_documents(arguments.dataset)
inverted_index = build_inverted_index(documents)
inverted_index.dump(arguments.output, arguments.strategy)
def callback_query(arguments):
"""Function for command 'query' is CLI
function print result of querys on loa inverted index"""
inverted_index = InvertedIndex.load(arguments.filepath)
for query in arguments.query:
document_ids = inverted_index.query(query)
print(*document_ids, sep=',')
def setup_parser(parser):
"""Function for developer CLI"""
subparsers = parser.add_subparsers(help="choose command")
build_parser = subparsers.add_parser(
"build", help="build inverted index and save into hard drive",
formatter_class=ArgumentDefaultsHelpFormatter,
)
build_parser.add_argument(
"-s", "--strategy", default="json", choices=['json', 'pickle'],
help="method to dump inverted index",
)
build_parser.add_argument(
"-d", "--dataset",
help="path to dataset to load", required=True,
)
build_parser.add_argument(
"-o", "--output",
help="path to store inverted index", required=True,
)
build_parser.set_defaults(callback=callback_build)
query_parser = subparsers.add_parser(
"query", help="print result of queries",
formatter_class=ArgumentDefaultsHelpFormatter,
)
query_parser.add_argument(
"-j", "--json-index", required=True,
help="path to store inverted index (in .json format)",
dest="filepath",
)
query_parser.add_argument(
"-q", "--query", help="set of words for query",
action="append", required=True, nargs="+",
)
query_parser.set_defaults(callback=callback_query)
def main():
parser = ArgumentParser(
prog="inverted_index",
description="Inverted Index CLI: tool to build, dump, load and query inverted index",
)
setup_parser(parser)
arguments = parser.parse_args()
arguments.callback(arguments)
if __name__ == "__main__":
main()