Skip to content
This repository was archived by the owner on May 9, 2026. It is now read-only.

Commit e475d76

Browse files
committed
Update Hansard example to work with HTML data
1 parent 795b1f5 commit e475d76

1 file changed

Lines changed: 47 additions & 77 deletions

File tree

examples/australian_federal_hansard/hansard_corpus.py

Lines changed: 47 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import traceback
1616
import zipfile
1717

18-
from lxml import etree
18+
from lxml import html
1919
from markupsafe import Markup
2020

2121
from hyperreal.index import Index
@@ -27,8 +27,6 @@
2727
class HansardCorpus(SqliteBackedCorpus):
2828
CORPUS_TYPE = "Australian Federal Hansard"
2929

30-
table_fields = ["date", "house", "debate_title", "subdebate_title", "speech"]
31-
3230
def __init__(self, db_path):
3331
"""
3432
A corpus to wrap around the data model found in https://github.com/SamHames/hansard-tidy
@@ -49,21 +47,18 @@ def docs(self, doc_keys=None):
4947
self.db.execute(
5048
"""
5149
select
52-
speech.speech_id,
53-
speech.date,
54-
speech.house,
55-
speech_number,
56-
debate.debate_id,
57-
debate.debate,
58-
debate.subdebate_1,
59-
debate.subdebate_2,
60-
xml_url,
61-
html_url,
62-
speech_xml
63-
from speech
50+
page_id,
51+
url,
52+
access_time,
53+
debate_id,
54+
pp.date,
55+
pp.house,
56+
pp.parl_no,
57+
title,
58+
page_html
59+
from proceedings_page pp
6460
inner join debate using(debate_id)
65-
inner join transcript using(transcript_id)
66-
where speech.speech_id = ?
61+
where page_id = ?
6762
""",
6863
[key],
6964
)
@@ -75,90 +70,60 @@ def docs(self, doc_keys=None):
7570
self.db.execute("release docs")
7671

7772
def index(self, doc):
78-
root = etree.fromstring(doc["speech_xml"])
79-
80-
# TODO: This will need additional work to work with all the different
81-
# hansard schemas.
82-
talkers = root.xpath("//talker")
83-
for elem in talkers:
84-
elem.clear()
73+
root = html.fromstring(doc["page_html"])
8574

86-
speech_tokens = tokens(" ".join(root.itertext()))
75+
page_tokens = tokens(" ".join(root.itertext()))
8776

88-
speech_date = date.fromisoformat(doc["date"])
89-
speech_month = speech_date.replace(day=1)
90-
speech_year = speech_month.replace(month=1)
77+
page_date = date.fromisoformat(doc["date"])
78+
month = page_date.replace(day=1)
79+
year = month.replace(month=1)
9180

9281
return {
93-
"speech": speech_tokens,
82+
"page": page_tokens,
9483
"house": set([doc["house"]]),
95-
"debate": set([doc["debate"]]),
96-
"subdebate_1": set([doc["subdebate_1"]]),
97-
"subdebate_2": set([doc["subdebate_2"]]),
9884
"debate_id": set([doc["debate_id"]]),
99-
"speech_date": set([speech_date.isoformat()]),
100-
"speech_month": set([speech_month.isoformat()]),
101-
"speech_year": set([speech_year.isoformat()]),
102-
}
103-
104-
def pretty_index(self, doc):
105-
root = etree.fromstring(doc["speech_xml"])
106-
107-
# TODO: This will need additional work to work with all the different
108-
# hansard schemas.
109-
talkers = root.xpath("//talker")
110-
for elem in talkers:
111-
elem.clear()
112-
113-
speech_tokens = presentable_tokens(" ".join(root.itertext()))
114-
115-
speech_date = date.fromisoformat(doc["date"])
116-
117-
return {
118-
"speech": speech_tokens,
119-
"house": set([doc["house"]]),
120-
"debate": set([doc["debate"]]),
121-
"subdebate_1": set([doc["subdebate_1"]]),
122-
"subdebate_2": set([doc["subdebate_2"]]),
123-
"speech_date": set([speech_date.isoformat()]),
124-
"transcript_url": set([doc["html_url"]]),
85+
"date": set([page_date.isoformat()]),
86+
"month": set([month.isoformat()]),
87+
"year": set([year.isoformat()]),
88+
"parl_no": set([doc["parl_no"]]),
89+
# Index the formatting elements so we can systematically investigate them
90+
"html_classes": {
91+
str(clss) for elem in root.iter() for clss in elem.classes
92+
},
93+
"html_tags": {str(elem.tag) for elem in root.iter()},
12594
}
12695

12796
def render_docs_html(self, doc_keys):
12897
"""Return the given documents as HTML."""
12998
docs = []
13099

131100
for key, doc in self.docs(doc_keys=doc_keys):
132-
tree = etree.fromstring(doc["speech_xml"])
133-
134-
text = " ".join(s for s in tree.itertext())
135-
text = "<br />".join(s for s in text.splitlines() if s.strip())
136-
137101
summary = ", ".join(
138-
doc[item]
139-
for item in ("date", "house", "debate", "subdebate_1", "subdebate_2")
140-
if doc[item]
102+
doc[item] for item in ("date", "house", "title") if doc[item]
141103
)
142104

143105
doc_html = """
144106
<details>
145107
<summary>{}</summary>
146108
<div>
147-
<a href="{}">See full day</a>
109+
<a href="{}">See in context</a>
148110
</div>
149111
<div>{}</div>
150112
</details>
151113
""".format(
152-
summary, doc["html_url"], text
114+
summary, doc["url"], doc["page_html"]
153115
)
154116

155117
docs.append((key, Markup(doc_html)))
156118

157119
return docs
158120

159121
def keys(self):
160-
"""The speeches are the central document."""
161-
return (r["speech_id"] for r in self.db.execute("select speech_id from speech"))
122+
"""The pages are the central document."""
123+
return (
124+
r["page_id"]
125+
for r in self.db.execute("select page_id from proceedings_page")
126+
)
162127

163128

164129
if __name__ == "__main__":
@@ -167,28 +132,33 @@ def keys(self):
167132
except FileNotFoundError:
168133
pass
169134

135+
db = "tidy_hansard.db"
136+
db_index = "tidy_hansard_index.db"
137+
170138
logging.basicConfig(filename="process_hansard.log", level=logging.INFO)
171-
corpus = HansardCorpus("hansard.db")
139+
corpus = HansardCorpus(db)
172140

173141
args = sys.argv[1:]
174142

175143
mp_context = mp.get_context("spawn")
176144
with cf.ProcessPoolExecutor(mp_context=mp_context) as pool:
177-
idx = Index("hansard_index.db", corpus=corpus, pool=pool)
145+
idx = Index(db_index, corpus=corpus, pool=pool)
178146

179147
if "index" in args:
180-
idx.index(doc_batch_size=100000, position_window_size=1)
148+
idx.index(doc_batch_size=50000, index_positions=True)
181149

182150
if "cluster" in args:
183151
idx.initialise_clusters(
184-
n_clusters=512, min_docs=10, include_fields=["speech"]
152+
n_clusters=256, min_docs=100, include_fields=["page"]
153+
)
154+
idx.refine_clusters(
155+
iterations=50, group_test_batches=32, group_test_top_k=2
185156
)
186-
idx.refine_clusters(iterations=50, group_test_batches=100)
187157

188158
index_server = hyperreal.server.SingleIndexServer(
189-
"hansard_index.db",
159+
db_index,
190160
corpus_class=HansardCorpus,
191-
corpus_args=["hansard.db"],
161+
corpus_args=[db],
192162
pool=pool,
193163
)
194164
engine = hyperreal.server.launch_web_server(index_server)

0 commit comments

Comments
 (0)