Skip to content

Commit 5e4cbbf

Browse files
committed
Working on week 6
1 parent e119169 commit 5e4cbbf

7 files changed

Lines changed: 311 additions & 2 deletions

File tree

‎.admin/policies/UseAIServices.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
"transcribe:*",
1010
"translate:*",
1111
"rekognition:*",
12-
"comprehend:*"
12+
"comprehend:*",
13+
"kendra:*"
1314
],
1415
"Resource": "*"
1516
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
CREATE DATABASE {{database_name}}
2+
-- Replace {{database_name}} with the name of your database
3+
-- No hyphens allowed in database names
4+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
DROP TABLE IF EXISTS {{database_name}}.bronze_edits;
2+
3+
CREATE EXTERNAL TABLE
4+
{{database_name}}.bronze_edits (
5+
title STRING,
6+
edits INT,
7+
date DATE,
8+
retrieved_at STRING)
9+
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
10+
LOCATION 's3://{{bucket_name}}/datalake/bronze_edits/';
Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
# %% Verification Functions
2+
import datetime
3+
import json
4+
from pathlib import Path
5+
6+
import boto3
7+
import requests
8+
9+
10+
def verify_lab1_solution(file_path, content):
11+
"""Verifies the lab 1 solution for saving raw Wikipedia data"""
12+
try:
13+
# Check directory
14+
print(f"📁 Checking folder {RAW_LOCATION_BASE}...")
15+
if not RAW_LOCATION_BASE.exists():
16+
print("❌ Required folder does not exist")
17+
return False
18+
print(f"✅ Folder {RAW_LOCATION_BASE} exists!")
19+
20+
# Check if file exists
21+
print(f"📄 Checking file {file_path}...")
22+
if not file_path.exists():
23+
print("❌ File does not exist")
24+
return False
25+
print(f"✅ File {file_path.name} exists!")
26+
27+
# Check file name format
28+
print("🔍 Checking file name format...")
29+
expected_name = f"raw-edits-{date.strftime('%Y-%m-%d')}.txt"
30+
if file_path.name != expected_name:
31+
print(f"❌ Incorrect file name. Expected: {expected_name}")
32+
return False
33+
print(f"✅ File name matches expected format: {expected_name}")
34+
35+
# Check file content
36+
print("📝 Checking file content...")
37+
with file_path.open("r") as f:
38+
file_content = f.read()
39+
if file_content != content:
40+
print("❌ File content does not match expected content")
41+
return False
42+
print("✅ File content matches expected data!")
43+
44+
# Check file location
45+
print("📍 Checking file location...")
46+
if str(RAW_LOCATION_BASE) not in str(file_path):
47+
print("❌ File not saved in correct directory")
48+
return False
49+
print("✅ File is in the correct directory!")
50+
51+
print("🌟 All checks passed for Lab 1!")
52+
return True
53+
54+
except Exception as e:
55+
print(f"❌ Error during verification: {str(e)}")
56+
return False
57+
58+
59+
def verify_bucket_name(bucket_name):
60+
"""Verifies the S3 bucket name format"""
61+
try:
62+
print("🔍 Checking bucket name format...")
63+
64+
# Check if bucket name is empty or default
65+
if not bucket_name or bucket_name == "<>":
66+
print("❌ Bucket name cannot be empty or default '<>'")
67+
return False
68+
print("✅ Bucket name is not empty!")
69+
70+
# Check if bucket name ends with -wikidata
71+
if not bucket_name.endswith("-wikidata"):
72+
print("❌ Bucket name must end with '-wikidata'")
73+
return False
74+
print("✅ Bucket name ends with '-wikidata'!")
75+
76+
# Check minimum length
77+
name_without_suffix = bucket_name[:-9] # Remove '-wikidata'
78+
if len(name_without_suffix) < 3:
79+
print("❌ Bucket name too short (excluding '-wikidata')")
80+
return False
81+
print("✅ Bucket name has valid length!")
82+
83+
print("🌟 Bucket name format is correct!")
84+
return True
85+
86+
except Exception as e:
87+
print(f"❌ Error during bucket name verification: {str(e)}")
88+
return False
89+
90+
91+
def verify_s3_upload(bucket, key, local_file):
92+
"""Verifies the S3 upload was successful"""
93+
try:
94+
print("🔍 Checking S3 upload...")
95+
96+
# Check if file exists in S3
97+
try:
98+
print(f"📡 Checking if file exists in S3 bucket {bucket}...")
99+
s3_obj = s3.head_object(Bucket=bucket, Key=key)
100+
print("✅ File found in S3!")
101+
except Exception:
102+
print("❌ File not found in S3")
103+
return False
104+
105+
# Check prefix
106+
print("📁 Checking S3 folder structure...")
107+
if not key.startswith("datalake/raw/"):
108+
print("❌ Incorrect S3 prefix. Must be 'datalake/raw/'")
109+
return False
110+
print("✅ File is in correct S3 folder!")
111+
112+
# Check file sizes match
113+
print("📊 Checking file sizes...")
114+
local_size = local_file.stat().st_size
115+
s3_size = s3_obj["ContentLength"]
116+
if local_size != s3_size:
117+
print("❌ File size mismatch between local and S3")
118+
return False
119+
print(f"✅ File sizes match: {local_size} bytes!")
120+
121+
# Check path format
122+
print("🔍 Checking S3 path format...")
123+
expected_key = f"datalake/raw/raw-edits-{date.strftime('%Y-%m-%d')}.txt"
124+
if key != expected_key:
125+
print(f"❌ Incorrect S3 key format. Expected: {expected_key}")
126+
return False
127+
print("✅ S3 path format is correct!")
128+
129+
print("🌟 All S3 upload checks passed!")
130+
return True
131+
132+
except Exception as e:
133+
print(f"❌ Error during S3 verification: {str(e)}")
134+
return False
135+
136+
137+
# %% Retrieve data from Wikipedia
138+
# SUBJECT DATE ### TRY A FEW OF THIS IN CLASS
139+
DATE_PARAM = "2024-11-25"
140+
141+
date = datetime.datetime.strptime(DATE_PARAM, "%Y-%m-%d")
142+
143+
# Wikimedia API URL formation
144+
# =============================================================================
145+
# Docs: https://doc.wikimedia.org/generated-data-platform/aqs/analytics-api/reference/edits.html#list-most-edited-pages-by-number-of-edits # noqa: E501
146+
# =============================================================================
147+
url = f"https://wikimedia.org/api/rest_v1/metrics/edited-pages/top-by-edits/en.wikipedia/user/content/{date.strftime('%Y/%m/%d')}" # noqa: E501
148+
print(f"Requesting REST API URL: {url}")
149+
150+
# Getting response from Wikimedia API
151+
wiki_server_response = requests.get(url, headers={"User-Agent": "curl/7.68.0"})
152+
wiki_response_status = wiki_server_response.status_code
153+
wiki_response_body = wiki_server_response.text
154+
155+
print(f"Wikipedia REST API Response body: {wiki_response_body}")
156+
print(f"Wikipedia REST API Response Code: {wiki_response_status}")
157+
158+
# Check if response status is not OK
159+
if wiki_response_status != 200:
160+
print(
161+
f"❌ Received non-OK status code from Wiki Server: {wiki_response_status}. Response body: {wiki_response_body}"
162+
)
163+
else:
164+
print(f"✅ Successfully retrieved Wikipedia data, content-length: {len(wiki_response_body)}")
165+
166+
# %% Set up local directory structure
167+
current_directory = Path(__file__).parent
168+
RAW_LOCATION_BASE = current_directory / "data" / "raw-edits"
169+
RAW_LOCATION_BASE.mkdir(exist_ok=True, parents=True)
170+
print(f"Created directory {RAW_LOCATION_BASE}")
171+
172+
# %% LAB
173+
#########
174+
# LAB 1 #
175+
#########
176+
# Save the contents of `wiki_response_body` to file called `raw-edits-YYYY-MM-DD.txt` in the folder
177+
# in variable `RAW_LOCATION_BASE`.
178+
# i.e: `data/raw-edits/raw-edits-2024-10-01.txt`.
179+
180+
# Solution:
181+
raw_edits_file = RAW_LOCATION_BASE / f"raw-edits-{date.strftime('%Y-%m-%d')}.txt"
182+
with raw_edits_file.open("w") as file:
183+
file.write(wiki_response_body)
184+
print(f"Saved raw edits to {raw_edits_file}")
185+
186+
# Verify solution
187+
if verify_lab1_solution(raw_edits_file, wiki_response_body):
188+
print("🎉 Lab 1 completed successfully!")
189+
else:
190+
print("❌ Lab 1 needs correction")
191+
192+
# %% LAB
193+
#########
194+
# LAB 2 #
195+
#########
196+
S3_WIKI_BUCKET = "<>"
197+
# Create a new bucket for your wikipedia pipeline
198+
# > Choose a name ending with "-wikidata"
199+
# > Store the bucket name in the variable S3_WIKI_BUCKET
200+
# > Create the bucket if it does not exist
201+
s3 = boto3.client("s3")
202+
203+
# Solution:
204+
S3_WIKI_BUCKET = "ceu-zoltan-wikidata"
205+
206+
if not verify_bucket_name(S3_WIKI_BUCKET):
207+
raise ValueError("Invalid bucket name")
208+
209+
bucket_names = [bucket["Name"] for bucket in s3.list_buckets()["Buckets"]]
210+
if S3_WIKI_BUCKET not in bucket_names:
211+
s3.create_bucket(
212+
Bucket=S3_WIKI_BUCKET,
213+
CreateBucketConfiguration={"LocationConstraint": "eu-west-1"},
214+
)
215+
print(f"✅ Created new bucket: {S3_WIKI_BUCKET}")
216+
else:
217+
print(f"ℹ️ Using existing bucket: {S3_WIKI_BUCKET}")
218+
219+
220+
# %%
221+
222+
# Check your solution
223+
assert S3_WIKI_BUCKET != "", "Please set the S3_WIKI_BUCKET variable"
224+
assert s3.list_objects(Bucket=S3_WIKI_BUCKET), "The bucket {S3_WIKI_BUCKET} does not exist"
225+
226+
# Verify bucket access
227+
try:
228+
s3.head_bucket(Bucket=S3_WIKI_BUCKET)
229+
print("✅ Bucket is accessible")
230+
except Exception as e:
231+
print(f"❌ Cannot access bucket: {str(e)}")
232+
raise
233+
234+
# %% LAB
235+
#########
236+
# LAB 3 #
237+
#########
238+
# Upload the file you created to S3.
239+
# - Place the file in S3 under a folder called `datalake/raw/`.
240+
# - Keep the file's name as `raw-edits-YYYY-MM-DD.txt` (where YYYY-MM-DD is the date of the file).
241+
# > Don't hardcode the date. Calculate it from the DATE_PARAM variable.
242+
# - Verify that the file is there (list the bucket in Python or on the AWS Website)
243+
244+
# Solution:
245+
s3_key = f"datalake/raw/raw-edits-{date.strftime('%Y-%m-%d')}.txt"
246+
res = s3.upload_file(
247+
raw_edits_file,
248+
S3_WIKI_BUCKET,
249+
s3_key,
250+
)
251+
print(f"Uploaded raw edits to s3://{S3_WIKI_BUCKET}/{s3_key}")
252+
253+
# Verify upload
254+
if verify_s3_upload(S3_WIKI_BUCKET, s3_key, raw_edits_file):
255+
print("🎉 Lab 3 completed successfully!")
256+
else:
257+
print("❌ Lab 3 needs correction")
258+
259+
# END OF LAB
260+
261+
# %% Process and transform the data
262+
wiki_response_parsed = wiki_server_response.json()
263+
top_edits = wiki_response_parsed["items"][0]["results"][0]["top"]
264+
265+
current_time = datetime.datetime.now(datetime.timezone.utc) # Always use UTC!!
266+
json_lines = ""
267+
for page in top_edits:
268+
record = {
269+
"title": page["page_title"],
270+
"edits": page["edits"],
271+
"date": date.strftime("%Y-%m-%d"),
272+
"retrieved_at": current_time.replace(
273+
tzinfo=None
274+
).isoformat(), # We need to remove tzinfo as Athena cannot work with offsets
275+
}
276+
json_lines += json.dumps(record) + "\n"
277+
278+
JSON_LOCATION_DIR = current_directory / "data" / "edits"
279+
JSON_LOCATION_DIR.mkdir(exist_ok=True, parents=True)
280+
print(f"Created directory {JSON_LOCATION_DIR}")
281+
print(f"JSON lines:\n{json_lines}")
282+
283+
# %% Save and upload processed data
284+
json_lines_filename = f"edits-{date.strftime('%Y-%m-%d')}.json"
285+
json_lines_file = JSON_LOCATION_DIR / json_lines_filename
286+
287+
with json_lines_file.open("w") as file:
288+
file.write(json_lines)
289+
290+
# Upload the JSON file
291+
s3.upload_file(json_lines_file, S3_WIKI_BUCKET, f"datalake/bronze_edits/{json_lines_filename}")
292+
print(f"✅ Uploaded processed data to s3://{S3_WIKI_BUCKET}/datalake/bronze_edits/{json_lines_filename}")
293+
# %%

‎lecture_notes/lecture2_AWS.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -998,7 +998,8 @@ In this example, we open a terminal command line session on our local computer.
998998
999999
Pitfall: One thing to watch out for is the following: the ssh address is based on your IP address and if you start and stop your instance the IP can change, changing the address you ssh into along with it (again, the value in the field Public DNS). If you've re-started your instance and are having trouble sshing, check that your address is correct.
10001000
1001-
## Step 12: Install NGINX
1001+
## Step 12: Install NGINX (
1002+
__This step is only for your reference, please follow the in-class instructions__
10021003
10031004
Now that we are in, let's set up NGINX:
10041005
1. **Update the OS**: Run the following command to apply all updates to your operating system:

0 commit comments

Comments
 (0)