Compare commits
4 Commits
2390d2d10c
...
1525a48561
| Author | SHA1 | Date | |
|---|---|---|---|
| 1525a48561 | |||
| 172e66865c | |||
| 9bc871285b | |||
| 7c9db519ac |
@@ -60,9 +60,6 @@ runs the Part 2 Spark sort.
|
|||||||
|
|
||||||
### Add new months — `add_months.sh YYYY-MM [YYYY-MM ...]`
|
### Add new months — `add_months.sh YYYY-MM [YYYY-MM ...]`
|
||||||
|
|
||||||
> **NOTE: written but not yet tested. Remove this notice after a
|
|
||||||
> successful end-to-end run.**
|
|
||||||
|
|
||||||
Use this for routine incremental updates. Runs Part 1 on only the
|
Use this for routine incremental updates. Runs Part 1 on only the
|
||||||
specified months, then appends the sorted output as a new layer of
|
specified months, then appends the sorted output as a new layer of
|
||||||
partition files alongside the existing ones. No existing data is
|
partition files alongside the existing ones. No existing data is
|
||||||
@@ -130,9 +127,6 @@ from a login node — it takes the number of nodes as its first argument.
|
|||||||
|
|
||||||
### Merge layers — `merge_layers.sh`
|
### Merge layers — `merge_layers.sh`
|
||||||
|
|
||||||
> **NOTE: written but not yet tested. Remove this notice after a
|
|
||||||
> successful end-to-end run.**
|
|
||||||
|
|
||||||
Use this to collapse accumulated layers from incremental adds into a
|
Use this to collapse accumulated layers from incremental adds into a
|
||||||
single clean layer. Reads the existing final datasets, re-sorts
|
single clean layer. Reads the existing final datasets, re-sorts
|
||||||
everything, writes to `.merging` temp paths, then atomically replaces the
|
everything, writes to `.merging` temp paths, then atomically replaces the
|
||||||
|
|||||||
@@ -108,15 +108,32 @@ parallel --joblog add_months_joblog.txt --results add_months_logs \
|
|||||||
# --- Part 2: sort new months into staging (Spark, single fat node) ----------
|
# --- Part 2: sort new months into staging (Spark, single fat node) ----------
|
||||||
|
|
||||||
source "$SPARK_CONF_DIR/spark-env.sh"
|
source "$SPARK_CONF_DIR/spark-env.sh"
|
||||||
|
export PYSPARK_PYTHON="$PYTHON"
|
||||||
|
|
||||||
|
# Compute executor resources from what spark-env.sh detected.
|
||||||
|
# One executor gets all worker cores and ~85% of worker memory (leaving
|
||||||
|
# headroom for the driver and overhead).
|
||||||
|
_EXEC_CORES=${SPARK_WORKER_CORES:-$(nproc)}
|
||||||
|
_WORKER_MEM_GB=${SPARK_WORKER_MEMORY%g}
|
||||||
|
_EXEC_MEM_GB=$(( _WORKER_MEM_GB * 85 / 100 ))
|
||||||
|
_DRIVER_MEM_GB=$(( _WORKER_MEM_GB * 10 / 100 ))
|
||||||
|
SPARK_SUBMIT_CONF=(
|
||||||
|
--conf "spark.executor.cores=${_EXEC_CORES}"
|
||||||
|
--conf "spark.executor.memory=${_EXEC_MEM_GB}g"
|
||||||
|
--conf "spark.driver.memory=${_DRIVER_MEM_GB}g"
|
||||||
|
)
|
||||||
|
|
||||||
start_spark_cluster.sh
|
start_spark_cluster.sh
|
||||||
|
|
||||||
spark-submit --master "spark://$(hostname):$SPARK_MASTER_PORT" \
|
spark-submit --master "spark://$(hostname):$SPARK_MASTER_PORT" \
|
||||||
|
"${SPARK_SUBMIT_CONF[@]}" \
|
||||||
comments_part2.py \
|
comments_part2.py \
|
||||||
--indir="$TEMP_COMMENTS" \
|
--indir="$TEMP_COMMENTS" \
|
||||||
--out_by_subreddit="$STAGING_COMMENTS_SUB" \
|
--out_by_subreddit="$STAGING_COMMENTS_SUB" \
|
||||||
--out_by_author="$STAGING_COMMENTS_AUTH"
|
--out_by_author="$STAGING_COMMENTS_AUTH"
|
||||||
|
|
||||||
spark-submit --master "spark://$(hostname):$SPARK_MASTER_PORT" \
|
spark-submit --master "spark://$(hostname):$SPARK_MASTER_PORT" \
|
||||||
|
"${SPARK_SUBMIT_CONF[@]}" \
|
||||||
submissions_part2.py \
|
submissions_part2.py \
|
||||||
--indir="$TEMP_SUBMISSIONS" \
|
--indir="$TEMP_SUBMISSIONS" \
|
||||||
--out_by_subreddit="$STAGING_SUBMISSIONS_SUB" \
|
--out_by_subreddit="$STAGING_SUBMISSIONS_SUB" \
|
||||||
|
|||||||
@@ -15,7 +15,9 @@ from dumps_helper import COMMENTS, sort_and_write
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
fire.Fire(lambda indir=None, out_by_subreddit=None, out_by_author=None:
|
fire.Fire(lambda indir=None, out_by_subreddit=None, out_by_author=None,
|
||||||
|
num_partitions=800:
|
||||||
sort_and_write(COMMENTS, indir=indir,
|
sort_and_write(COMMENTS, indir=indir,
|
||||||
out_by_subreddit=out_by_subreddit,
|
out_by_subreddit=out_by_subreddit,
|
||||||
out_by_author=out_by_author))
|
out_by_author=out_by_author,
|
||||||
|
num_partitions=num_partitions))
|
||||||
|
|||||||
@@ -256,7 +256,8 @@ def gen_task_list(config, script_name, dumpdir=None, tasklist=None):
|
|||||||
|
|
||||||
# --- Part 2: spark sort + repartition --------------------------------------
|
# --- Part 2: spark sort + repartition --------------------------------------
|
||||||
|
|
||||||
def sort_and_write(config, indir=None, out_by_subreddit=None, out_by_author=None):
|
def sort_and_write(config, indir=None, out_by_subreddit=None, out_by_author=None,
|
||||||
|
num_partitions=None):
|
||||||
"""Read a directory of per-source parquets, sort and repartition twice
|
"""Read a directory of per-source parquets, sort and repartition twice
|
||||||
(once by subreddit, once by author), and write the two output datasets.
|
(once by subreddit, once by author), and write the two output datasets.
|
||||||
|
|
||||||
@@ -265,6 +266,11 @@ def sort_and_write(config, indir=None, out_by_subreddit=None, out_by_author=None
|
|||||||
and config['output_by_author']. Override them to write to staging directories
|
and config['output_by_author']. Override them to write to staging directories
|
||||||
instead of the live datasets (see add_months.sh).
|
instead of the live datasets (see add_months.sh).
|
||||||
|
|
||||||
|
num_partitions controls the number of output files per dataset. Target
|
||||||
|
~1GB per output file: use ~800 for a full 16-month comments batch,
|
||||||
|
~300 for submissions. Defaults to config['num_partitions'] if set,
|
||||||
|
otherwise 200.
|
||||||
|
|
||||||
Pyspark is imported lazily so Part 1 callers don't pay the Spark startup
|
Pyspark is imported lazily so Part 1 callers don't pay the Spark startup
|
||||||
cost.
|
cost.
|
||||||
"""
|
"""
|
||||||
@@ -273,6 +279,7 @@ def sort_and_write(config, indir=None, out_by_subreddit=None, out_by_author=None
|
|||||||
indir = indir or config['outdir']
|
indir = indir or config['outdir']
|
||||||
out_by_subreddit = out_by_subreddit or config['output_by_subreddit']
|
out_by_subreddit = out_by_subreddit or config['output_by_subreddit']
|
||||||
out_by_author = out_by_author or config['output_by_author']
|
out_by_author = out_by_author or config['output_by_author']
|
||||||
|
num_partitions = num_partitions or config.get('num_partitions', 200)
|
||||||
|
|
||||||
spark = SparkSession.builder.appName(config['app_name']).getOrCreate()
|
spark = SparkSession.builder.appName(config['app_name']).getOrCreate()
|
||||||
|
|
||||||
@@ -287,16 +294,21 @@ def sort_and_write(config, indir=None, out_by_subreddit=None, out_by_author=None
|
|||||||
df = df.withColumn("Year", f.year(f.col("CreatedAt")))
|
df = df.withColumn("Year", f.year(f.col("CreatedAt")))
|
||||||
df = df.withColumn("Day", f.dayofmonth(f.col("CreatedAt")))
|
df = df.withColumn("Day", f.dayofmonth(f.col("CreatedAt")))
|
||||||
|
|
||||||
|
# Cache after preprocessing so the input is not re-read for each sort.
|
||||||
|
df = df.cache()
|
||||||
|
|
||||||
sub_keys = config['subreddit_sort_keys']
|
sub_keys = config['subreddit_sort_keys']
|
||||||
df_sub = df.repartition('subreddit').sort(sub_keys, ascending=True)
|
df_sub = df.repartition(num_partitions, 'subreddit').sort(sub_keys, ascending=True)
|
||||||
df_sub = df_sub.sortWithinPartitions(sub_keys, ascending=True)
|
df_sub = df_sub.sortWithinPartitions(sub_keys, ascending=True)
|
||||||
df_sub.write.parquet(out_by_subreddit, mode='overwrite', compression='snappy')
|
df_sub.write.parquet(out_by_subreddit, mode='overwrite', compression='snappy')
|
||||||
|
|
||||||
auth_keys = config['author_sort_keys']
|
auth_keys = config['author_sort_keys']
|
||||||
df_auth = df.repartition('author').sort(auth_keys, ascending=True)
|
df_auth = df.repartition(num_partitions, 'author').sort(auth_keys, ascending=True)
|
||||||
df_auth = df_auth.sortWithinPartitions(auth_keys, ascending=True)
|
df_auth = df_auth.sortWithinPartitions(auth_keys, ascending=True)
|
||||||
df_auth.write.parquet(out_by_author, mode='overwrite', compression='snappy')
|
df_auth.write.parquet(out_by_author, mode='overwrite', compression='snappy')
|
||||||
|
|
||||||
|
df.unpersist()
|
||||||
|
|
||||||
|
|
||||||
def merge_layers(config):
|
def merge_layers(config):
|
||||||
"""Collapse all accumulated layers in the final datasets into a single
|
"""Collapse all accumulated layers in the final datasets into a single
|
||||||
|
|||||||
@@ -15,7 +15,9 @@ from dumps_helper import SUBMISSIONS, sort_and_write
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
fire.Fire(lambda indir=None, out_by_subreddit=None, out_by_author=None:
|
fire.Fire(lambda indir=None, out_by_subreddit=None, out_by_author=None,
|
||||||
|
num_partitions=300:
|
||||||
sort_and_write(SUBMISSIONS, indir=indir,
|
sort_and_write(SUBMISSIONS, indir=indir,
|
||||||
out_by_subreddit=out_by_subreddit,
|
out_by_subreddit=out_by_subreddit,
|
||||||
out_by_author=out_by_author))
|
out_by_author=out_by_author,
|
||||||
|
num_partitions=num_partitions))
|
||||||
|
|||||||
Reference in New Issue
Block a user