Spaces:
Runtime error
Runtime error
Upload folder using huggingface_hub
Browse files- .gitattributes +2 -35
- README.md +6 -5
- app.py +94 -0
- data/.gitkeep +0 -0
- data/data-00000-of-00001.arrow +3 -0
- data/dataset_info.json +63 -0
- data/state.json +13 -0
- index/.gitkeep +0 -0
- index/_5.fdm +0 -0
- index/_5.fdt +0 -0
- index/_5.fdx +0 -0
- index/_5.fnm +0 -0
- index/_5.nvd +0 -0
- index/_5.nvm +0 -0
- index/_5.si +0 -0
- index/_5_Lucene90_0.doc +3 -0
- index/_5_Lucene90_0.dvd +0 -0
- index/_5_Lucene90_0.dvm +0 -0
- index/_5_Lucene90_0.pos +3 -0
- index/_5_Lucene90_0.tim +3 -0
- index/_5_Lucene90_0.tip +0 -0
- index/_5_Lucene90_0.tmd +0 -0
- index/segments_2 +0 -0
- index/write.lock +0 -0
- packages.txt +1 -0
- requirements.txt +4 -0
- spacerini_utils/__init__.py +0 -0
- spacerini_utils/__pycache__/__init__.cpython-39.pyc +0 -0
- spacerini_utils/__pycache__/index.cpython-39.pyc +0 -0
- spacerini_utils/__pycache__/search.cpython-39.pyc +0 -0
- spacerini_utils/index.py +20 -0
- spacerini_utils/search.py +135 -0
.gitattributes
CHANGED
@@ -1,35 +1,2 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
*.bin filter=lfs diff=lfs merge=lfs -text
|
4 |
-
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
5 |
-
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
6 |
-
*.ftz filter=lfs diff=lfs merge=lfs -text
|
7 |
-
*.gz filter=lfs diff=lfs merge=lfs -text
|
8 |
-
*.h5 filter=lfs diff=lfs merge=lfs -text
|
9 |
-
*.joblib filter=lfs diff=lfs merge=lfs -text
|
10 |
-
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
12 |
-
*.model filter=lfs diff=lfs merge=lfs -text
|
13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
16 |
-
*.onnx filter=lfs diff=lfs merge=lfs -text
|
17 |
-
*.ot filter=lfs diff=lfs merge=lfs -text
|
18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
22 |
-
*.pt filter=lfs diff=lfs merge=lfs -text
|
23 |
-
*.pth filter=lfs diff=lfs merge=lfs -text
|
24 |
-
*.rar filter=lfs diff=lfs merge=lfs -text
|
25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
26 |
-
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
27 |
-
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
29 |
-
*.tflite filter=lfs diff=lfs merge=lfs -text
|
30 |
-
*.tgz filter=lfs diff=lfs merge=lfs -text
|
31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
32 |
-
*.xz filter=lfs diff=lfs merge=lfs -text
|
33 |
-
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
-
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
1 |
+
index/**/* filter=lfs diff=lfs merge=lfs -text
|
2 |
+
data/data-00000-of-00001.arrow filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
README.md
CHANGED
@@ -1,12 +1,13 @@
|
|
1 |
---
|
2 |
-
title:
|
3 |
-
emoji:
|
4 |
colorFrom: blue
|
5 |
-
colorTo:
|
6 |
sdk: gradio
|
7 |
-
sdk_version: 3.
|
8 |
app_file: app.py
|
9 |
pinned: false
|
|
|
10 |
---
|
11 |
|
12 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
1 |
---
|
2 |
+
title: IMDB search
|
3 |
+
emoji: 🐠
|
4 |
colorFrom: blue
|
5 |
+
colorTo: blue
|
6 |
sdk: gradio
|
7 |
+
sdk_version: 3.29.0
|
8 |
app_file: app.py
|
9 |
pinned: false
|
10 |
+
license: apache-2.0
|
11 |
---
|
12 |
|
13 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
app.py
ADDED
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from datasets import load_from_disk
|
3 |
+
from pyserini.search.lucene import LuceneSearcher
|
4 |
+
|
5 |
+
searcher = LuceneSearcher("index")
|
6 |
+
ds = load_from_disk("data")
|
7 |
+
NUM_PAGES = 10 # STATIC. THIS CAN'T CHANGE BECAUSE GRADIO CAN'T DYNAMICALLY CREATE COMPONENTS.
|
8 |
+
RESULTS_PER_PAGE = 5
|
9 |
+
|
10 |
+
TEXT_FIELD = "text"
|
11 |
+
METADATA_FIELD = "label"
|
12 |
+
|
13 |
+
|
14 |
+
def result_html(result, meta):
|
15 |
+
return (
|
16 |
+
f"<div style=\"color:#2a5cb3;font-weight: 500\"><u>{meta}</u></div><br>"
|
17 |
+
f"<div><details><summary>{result[:250]}...</summary><p>{result[250:]}</p></details></div><br><hr><br>"
|
18 |
+
)
|
19 |
+
|
20 |
+
|
21 |
+
def format_results(results):
|
22 |
+
return "\n".join([result_html(result, meta) for result,meta in zip(results[TEXT_FIELD], results[METADATA_FIELD])])
|
23 |
+
|
24 |
+
|
25 |
+
def page_0(query):
|
26 |
+
hits = searcher.search(query, k=NUM_PAGES*RESULTS_PER_PAGE)
|
27 |
+
ix = [int(hit.docid) for hit in hits]
|
28 |
+
results = ds.select(ix).shard(num_shards=NUM_PAGES, index=0, contiguous=True) # no need to shard. split ix in batches instead. (would make sense if results was cacheable)
|
29 |
+
results = format_results(results)
|
30 |
+
return results, [ix], gr.update(visible=True)
|
31 |
+
|
32 |
+
|
33 |
+
def page_i(i, ix):
|
34 |
+
ix = ix[0]
|
35 |
+
results = ds.select(ix).shard(num_shards=NUM_PAGES, index=i, contiguous=True)
|
36 |
+
results = format_results(results)
|
37 |
+
return results, [ix]
|
38 |
+
|
39 |
+
|
40 |
+
with gr.Blocks(css="#b {min-width:15px;background:transparent;border:white;box-shadow:none;}") as demo: #
|
41 |
+
with gr.Row():
|
42 |
+
gr.Markdown(value="""## <p style="text-align: center;"> IMDB search </p>""")
|
43 |
+
with gr.Row():
|
44 |
+
with gr.Column(scale=1):
|
45 |
+
result_list = gr.Dataframe(type="array", visible=False, col_count=1)
|
46 |
+
with gr.Column(scale=13):
|
47 |
+
query = gr.Textbox(lines=1, max_lines=1, placeholder="Search…", label="")
|
48 |
+
with gr.Column(scale=1):
|
49 |
+
with gr.Row(scale=1):
|
50 |
+
pass
|
51 |
+
with gr.Row(scale=1):
|
52 |
+
submit_btn = gr.Button("🔍", elem_id="b").style(full_width=False)
|
53 |
+
with gr.Row(scale=1):
|
54 |
+
pass
|
55 |
+
|
56 |
+
with gr.Row():
|
57 |
+
with gr.Column(scale=1):
|
58 |
+
pass
|
59 |
+
with gr.Column(scale=13):
|
60 |
+
c = gr.HTML(label="Results")
|
61 |
+
with gr.Row(visible=False) as pagination:
|
62 |
+
# left = gr.Button(value="◀", elem_id="b", visible=False).style(full_width=True)
|
63 |
+
page_1 = gr.Button(value="1", elem_id="b").style(full_width=True)
|
64 |
+
page_2 = gr.Button(value="2", elem_id="b").style(full_width=True)
|
65 |
+
page_3 = gr.Button(value="3", elem_id="b").style(full_width=True)
|
66 |
+
page_4 = gr.Button(value="4", elem_id="b").style(full_width=True)
|
67 |
+
page_5 = gr.Button(value="5", elem_id="b").style(full_width=True)
|
68 |
+
page_6 = gr.Button(value="6", elem_id="b").style(full_width=True)
|
69 |
+
page_7 = gr.Button(value="7", elem_id="b").style(full_width=True)
|
70 |
+
page_8 = gr.Button(value="8", elem_id="b").style(full_width=True)
|
71 |
+
page_9 = gr.Button(value="9", elem_id="b").style(full_width=True)
|
72 |
+
page_10 = gr.Button(value="10", elem_id="b").style(full_width=True)
|
73 |
+
# right = gr.Button(value="▶", elem_id="b", visible=False).style(full_width=True)
|
74 |
+
with gr.Column(scale=1):
|
75 |
+
pass
|
76 |
+
|
77 |
+
query.submit(fn=page_0, inputs=[query], outputs=[c, result_list, pagination])
|
78 |
+
submit_btn.click(page_0, inputs=[query], outputs=[c, result_list, pagination])
|
79 |
+
|
80 |
+
with gr.Box(visible=False):
|
81 |
+
nums = [gr.Number(i, visible=False, precision=0) for i in range(NUM_PAGES)]
|
82 |
+
|
83 |
+
page_1.click(fn=page_i, inputs=[nums[0], result_list], outputs=[c, result_list])
|
84 |
+
page_2.click(fn=page_i, inputs=[nums[1], result_list], outputs=[c, result_list])
|
85 |
+
page_3.click(fn=page_i, inputs=[nums[2], result_list], outputs=[c, result_list])
|
86 |
+
page_4.click(fn=page_i, inputs=[nums[3], result_list], outputs=[c, result_list])
|
87 |
+
page_5.click(fn=page_i, inputs=[nums[4], result_list], outputs=[c, result_list])
|
88 |
+
page_6.click(fn=page_i, inputs=[nums[5], result_list], outputs=[c, result_list])
|
89 |
+
page_7.click(fn=page_i, inputs=[nums[6], result_list], outputs=[c, result_list])
|
90 |
+
page_8.click(fn=page_i, inputs=[nums[7], result_list], outputs=[c, result_list])
|
91 |
+
page_9.click(fn=page_i, inputs=[nums[8], result_list], outputs=[c, result_list])
|
92 |
+
page_10.click(fn=page_i, inputs=[nums[9], result_list], outputs=[c, result_list])
|
93 |
+
|
94 |
+
demo.launch(enable_queue=True, debug=True)
|
data/.gitkeep
ADDED
File without changes
|
data/data-00000-of-00001.arrow
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:ccad9a2cace25de89d2198d210317033e23de1a8175d1be4faafec3ceb187b20
|
3 |
+
size 66094864
|
data/dataset_info.json
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"builder_name": "imdb",
|
3 |
+
"citation": "@InProceedings{maas-EtAl:2011:ACL-HLT2011,\n author = {Maas, Andrew L. and Daly, Raymond E. and Pham, Peter T. and Huang, Dan and Ng, Andrew Y. and Potts, Christopher},\n title = {Learning Word Vectors for Sentiment Analysis},\n booktitle = {Proceedings of the 49th Annual Meeting of the Association for Computational Linguistics: Human Language Technologies},\n month = {June},\n year = {2011},\n address = {Portland, Oregon, USA},\n publisher = {Association for Computational Linguistics},\n pages = {142--150},\n url = {http://www.aclweb.org/anthology/P11-1015}\n}\n",
|
4 |
+
"config_name": "plain_text",
|
5 |
+
"dataset_size": 133190302,
|
6 |
+
"description": "Large Movie Review Dataset.\nThis is a dataset for binary sentiment classification containing substantially more data than previous benchmark datasets. We provide a set of 25,000 highly polar movie reviews for training, and 25,000 for testing. There is additional unlabeled data for use as well.",
|
7 |
+
"download_checksums": {
|
8 |
+
"https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz": {
|
9 |
+
"num_bytes": 84125825,
|
10 |
+
"checksum": null
|
11 |
+
}
|
12 |
+
},
|
13 |
+
"download_size": 84125825,
|
14 |
+
"features": {
|
15 |
+
"text": {
|
16 |
+
"dtype": "string",
|
17 |
+
"_type": "Value"
|
18 |
+
},
|
19 |
+
"label": {
|
20 |
+
"names": [
|
21 |
+
"neg",
|
22 |
+
"pos"
|
23 |
+
],
|
24 |
+
"_type": "ClassLabel"
|
25 |
+
}
|
26 |
+
},
|
27 |
+
"homepage": "http://ai.stanford.edu/~amaas/data/sentiment/",
|
28 |
+
"license": "",
|
29 |
+
"size_in_bytes": 217316127,
|
30 |
+
"splits": {
|
31 |
+
"train": {
|
32 |
+
"name": "train",
|
33 |
+
"num_bytes": 33432823,
|
34 |
+
"num_examples": 25000,
|
35 |
+
"dataset_name": "imdb"
|
36 |
+
},
|
37 |
+
"test": {
|
38 |
+
"name": "test",
|
39 |
+
"num_bytes": 32650685,
|
40 |
+
"num_examples": 25000,
|
41 |
+
"dataset_name": "imdb"
|
42 |
+
},
|
43 |
+
"unsupervised": {
|
44 |
+
"name": "unsupervised",
|
45 |
+
"num_bytes": 67106794,
|
46 |
+
"num_examples": 50000,
|
47 |
+
"dataset_name": "imdb"
|
48 |
+
}
|
49 |
+
},
|
50 |
+
"task_templates": [
|
51 |
+
{
|
52 |
+
"task": "text-classification",
|
53 |
+
"label_column": "label"
|
54 |
+
}
|
55 |
+
],
|
56 |
+
"version": {
|
57 |
+
"version_str": "1.0.0",
|
58 |
+
"description": "",
|
59 |
+
"major": 1,
|
60 |
+
"minor": 0,
|
61 |
+
"patch": 0
|
62 |
+
}
|
63 |
+
}
|
data/state.json
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"_data_files": [
|
3 |
+
{
|
4 |
+
"filename": "data-00000-of-00001.arrow"
|
5 |
+
}
|
6 |
+
],
|
7 |
+
"_fingerprint": "079439276ed0dd9a",
|
8 |
+
"_format_columns": null,
|
9 |
+
"_format_kwargs": {},
|
10 |
+
"_format_type": null,
|
11 |
+
"_output_all_columns": false,
|
12 |
+
"_split": "train+test"
|
13 |
+
}
|
index/.gitkeep
ADDED
File without changes
|
index/_5.fdm
ADDED
Binary file (158 Bytes). View file
|
|
index/_5.fdt
ADDED
Binary file (284 kB). View file
|
|
index/_5.fdx
ADDED
Binary file (247 Bytes). View file
|
|
index/_5.fnm
ADDED
Binary file (322 Bytes). View file
|
|
index/_5.nvd
ADDED
Binary file (50.1 kB). View file
|
|
index/_5.nvm
ADDED
Binary file (103 Bytes). View file
|
|
index/_5.si
ADDED
Binary file (534 Bytes). View file
|
|
index/_5_Lucene90_0.doc
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:c51f857a0b58e236592cfe90fe106dcf7a5d0834dfea20e0d26be498e696bd1d
|
3 |
+
size 7539565
|
index/_5_Lucene90_0.dvd
ADDED
Binary file (314 kB). View file
|
|
index/_5_Lucene90_0.dvm
ADDED
Binary file (171 Bytes). View file
|
|
index/_5_Lucene90_0.pos
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:b9e28efcc32c72172e4e2f83cf00dddd5cbfe8f9c25289d806022c3a97f14254
|
3 |
+
size 9575136
|
index/_5_Lucene90_0.tim
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:94b77d8179588eba0fec5f782efd2d42466182b5988e5463683c148ea415b087
|
3 |
+
size 1043047
|
index/_5_Lucene90_0.tip
ADDED
Binary file (26.6 kB). View file
|
|
index/_5_Lucene90_0.tmd
ADDED
Binary file (262 Bytes). View file
|
|
index/segments_2
ADDED
Binary file (154 Bytes). View file
|
|
index/write.lock
ADDED
File without changes
|
packages.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
default-jdk
|
requirements.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
pyserini
|
2 |
+
datasets
|
3 |
+
faiss-cpu
|
4 |
+
torch
|
spacerini_utils/__init__.py
ADDED
File without changes
|
spacerini_utils/__pycache__/__init__.cpython-39.pyc
ADDED
Binary file (161 Bytes). View file
|
|
spacerini_utils/__pycache__/index.cpython-39.pyc
ADDED
Binary file (769 Bytes). View file
|
|
spacerini_utils/__pycache__/search.cpython-39.pyc
ADDED
Binary file (4.41 kB). View file
|
|
spacerini_utils/index.py
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from typing import Any
|
3 |
+
from typing import Dict
|
4 |
+
|
5 |
+
from pyserini.index.lucene import IndexReader
|
6 |
+
|
7 |
+
|
8 |
+
def fetch_index_stats(index_path: str) -> Dict[str, Any]:
|
9 |
+
"""
|
10 |
+
Fetch index statistics
|
11 |
+
index_path : str
|
12 |
+
Path to index directory
|
13 |
+
Returns
|
14 |
+
-------
|
15 |
+
Dictionary of index statistics
|
16 |
+
Dictionary Keys ==> total_terms, documents, unique_terms
|
17 |
+
"""
|
18 |
+
assert os.path.exists(index_path), f"Index path {index_path} does not exist"
|
19 |
+
index_reader = IndexReader(index_path)
|
20 |
+
return index_reader.stats()
|
spacerini_utils/search.py
ADDED
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
from typing import List, Literal, Protocol, Tuple, TypedDict, Union
|
3 |
+
|
4 |
+
from pyserini.analysis import get_lucene_analyzer
|
5 |
+
from pyserini.index import IndexReader
|
6 |
+
from pyserini.search import DenseSearchResult, JLuceneSearcherResult
|
7 |
+
from pyserini.search.faiss.__main__ import init_query_encoder
|
8 |
+
from pyserini.search.faiss import FaissSearcher
|
9 |
+
from pyserini.search.hybrid import HybridSearcher
|
10 |
+
from pyserini.search.lucene import LuceneSearcher
|
11 |
+
|
12 |
+
EncoderClass = Literal["dkrr", "dpr", "tct_colbert", "ance", "sentence", "contriever", "auto"]
|
13 |
+
|
14 |
+
|
15 |
+
class AnalyzerArgs(TypedDict):
|
16 |
+
language: str
|
17 |
+
stemming: bool
|
18 |
+
stemmer: str
|
19 |
+
stopwords: bool
|
20 |
+
huggingFaceTokenizer: str
|
21 |
+
|
22 |
+
|
23 |
+
class SearchResult(TypedDict):
|
24 |
+
docid: str
|
25 |
+
text: str
|
26 |
+
score: float
|
27 |
+
language: str
|
28 |
+
|
29 |
+
|
30 |
+
class Searcher(Protocol):
|
31 |
+
def search(self, query: str, **kwargs) -> List[Union[DenseSearchResult, JLuceneSearcherResult]]:
|
32 |
+
...
|
33 |
+
|
34 |
+
|
35 |
+
def init_searcher_and_reader(
|
36 |
+
sparse_index_path: str = None,
|
37 |
+
bm25_k1: float = None,
|
38 |
+
bm25_b: float = None,
|
39 |
+
analyzer_args: AnalyzerArgs = None,
|
40 |
+
dense_index_path: str = None,
|
41 |
+
encoder_name_or_path: str = None,
|
42 |
+
encoder_class: EncoderClass = None,
|
43 |
+
tokenizer_name: str = None,
|
44 |
+
device: str = None,
|
45 |
+
prefix: str = None
|
46 |
+
) -> Tuple[Union[FaissSearcher, HybridSearcher, LuceneSearcher], IndexReader]:
|
47 |
+
"""
|
48 |
+
Initialize and return an approapriate searcher
|
49 |
+
|
50 |
+
Parameters
|
51 |
+
----------
|
52 |
+
sparse_index_path: str
|
53 |
+
Path to sparse index
|
54 |
+
dense_index_path: str
|
55 |
+
Path to dense index
|
56 |
+
encoder_name_or_path: str
|
57 |
+
Path to query encoder checkpoint or encoder name
|
58 |
+
encoder_class: str
|
59 |
+
Query encoder class to use. If None, infer from `encoder`
|
60 |
+
tokenizer_name: str
|
61 |
+
Tokenizer name or path
|
62 |
+
device: str
|
63 |
+
Device to load Query encoder on.
|
64 |
+
prefix: str
|
65 |
+
Query prefix if exists
|
66 |
+
|
67 |
+
Returns
|
68 |
+
-------
|
69 |
+
Searcher: FaissSearcher | HybridSearcher | LuceneSearcher
|
70 |
+
A sparse, dense or hybrid searcher
|
71 |
+
"""
|
72 |
+
reader = None
|
73 |
+
if sparse_index_path:
|
74 |
+
ssearcher = LuceneSearcher(sparse_index_path)
|
75 |
+
if analyzer_args:
|
76 |
+
analyzer = get_lucene_analyzer(**analyzer_args)
|
77 |
+
ssearcher.set_analyzer(analyzer)
|
78 |
+
if bm25_k1 and bm25_b:
|
79 |
+
ssearcher.set_bm25(bm25_k1, bm25_b)
|
80 |
+
|
81 |
+
if dense_index_path:
|
82 |
+
encoder = init_query_encoder(
|
83 |
+
encoder=encoder_name_or_path,
|
84 |
+
encoder_class=encoder_class,
|
85 |
+
tokenizer_name=tokenizer_name,
|
86 |
+
topics_name=None,
|
87 |
+
encoded_queries=None,
|
88 |
+
device=device,
|
89 |
+
prefix=prefix
|
90 |
+
)
|
91 |
+
|
92 |
+
reader = IndexReader(sparse_index_path)
|
93 |
+
dsearcher = FaissSearcher(dense_index_path, encoder)
|
94 |
+
|
95 |
+
if sparse_index_path:
|
96 |
+
hsearcher = HybridSearcher(dense_searcher=dsearcher, sparse_searcher=ssearcher)
|
97 |
+
return hsearcher, reader
|
98 |
+
else:
|
99 |
+
return dsearcher, reader
|
100 |
+
|
101 |
+
return ssearcher, reader
|
102 |
+
|
103 |
+
|
104 |
+
def _search(searcher: Searcher, reader: IndexReader, query: str, num_results: int = 10) -> List[SearchResult]:
|
105 |
+
"""
|
106 |
+
Parameters:
|
107 |
+
-----------
|
108 |
+
searcher: FaissSearcher | HybridSearcher | LuceneSearcher
|
109 |
+
A sparse, dense or hybrid searcher
|
110 |
+
query: str
|
111 |
+
Query for which to retrieve results
|
112 |
+
num_results: int
|
113 |
+
Maximum number of results to retrieve
|
114 |
+
|
115 |
+
Returns:
|
116 |
+
--------
|
117 |
+
Dict:
|
118 |
+
"""
|
119 |
+
def _get_dict(r: Union[DenseSearchResult, JLuceneSearcherResult]):
|
120 |
+
if isinstance(r, JLuceneSearcherResult):
|
121 |
+
return json.loads(r.raw)
|
122 |
+
elif isinstance(r, DenseSearchResult):
|
123 |
+
# Get document from sparse_index using index reader
|
124 |
+
return json.loads(reader.doc(r.docid).raw())
|
125 |
+
|
126 |
+
search_results = searcher.search(query, k=num_results)
|
127 |
+
all_results = [
|
128 |
+
SearchResult(
|
129 |
+
docid=result["id"],
|
130 |
+
text=result["contents"],
|
131 |
+
score=search_results[idx].score
|
132 |
+
) for idx, result in enumerate(map(lambda r: _get_dict(r), search_results))
|
133 |
+
]
|
134 |
+
|
135 |
+
return all_results
|