{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "bd02-title",
   "metadata": {},
   "source": [
    "# ⚡ 02 · Spark：RDD / 惰性求值 / 血缘 / 内存计算\n",
    "\n",
    "> Spark 是离线大数据的**事实标准**。本节不装 Spark，用 Python 模拟核心机制：\n",
    "> **RDD 转换（transformation）、惰性求值、血缘（lineage）、action 触发、Shuffle 与宽窄依赖**。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd02-q",
   "metadata": {},
   "source": [
    "## 📋 本节要解决的问题\n",
    "\n",
    "| # | 问题 | 方法 |\n",
    "|---|---|---|\n",
    "| 1 | RDD 是什么？ | 弹性分布式数据集（分区+转换） |\n",
    "| 2 | 惰性求值怎么工作？ | transformation 攒着，action 才执行 |\n",
    "| 3 | 血缘（lineage）干什么？ | 记录来源，故障重算 |\n",
    "| 4 | 宽窄依赖区别？ | 窄=同分区，宽=Shuffle |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "bd02-setup",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:43:35.718611Z",
     "iopub.status.busy": "2026-10-08T09:43:35.717703Z",
     "iopub.status.idle": "2026-10-08T09:43:53.638555Z",
     "shell.execute_reply": "2026-10-08T09:43:53.635647Z"
    }
   },
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib\n",
    "import matplotlib.pyplot as plt\n",
    "matplotlib.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimHei', 'PingFang SC', 'Noto Sans CJK SC', 'Arial Unicode MS']\n",
    "matplotlib.rcParams['axes.unicode_minus'] = False\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import sqlite3\n",
    "import os\n",
    "rng = np.random.default_rng(42)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd02-1",
   "metadata": {},
   "source": [
    "## 1️⃣ Spark 核心概念（必背）"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c25c3b3e",
   "metadata": {},
   "source": [
    "### Spark 生态与\"为什么快\"\n",
    "\n",
    "| 组件 | 作用 |\n",
    "|---|---|\n",
    "| Spark Core | RDD 抽象、任务调度、内存管理 |\n",
    "| Spark SQL | DataFrame/Dataset + Catalyst 优化器（生产主力） |\n",
    "| Structured Streaming | 流式处理（增量查询模型） |\n",
    "| MLlib | 分布式机器学习 |\n",
    "\n",
    "**比 MapReduce 快在哪**：MR 每个作业的中间结果必须**落盘**再由下一个作业读取（磁盘 IO 重）；\n",
    "Spark 把多步转换组成 **DAG**，窄依赖之间**流水线执行**（一批数据在一台机器上连续 map→filter，不落地），\n",
    "只有宽依赖（Shuffle）才真正交换数据——迭代类算法（机器学习常见）可快 10~100 倍。\n",
    "\n",
    "**RDD 的\"弹性\"**体现在三点：①分区可并行；②血缘可**重算**恢复；③可**缓存/释放**在内存与磁盘间切换。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "bd02-concept",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:43:53.660564Z",
     "iopub.status.busy": "2026-10-08T09:43:53.658773Z",
     "iopub.status.idle": "2026-10-08T09:43:53.717860Z",
     "shell.execute_reply": "2026-10-08T09:43:53.715088Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Spark 核心：\n",
      "  1) RDD：不可变、分区的数据集合（弹性=可重算、可缓存）；\n",
      "  2) Transformation：map/filter/flatMap/groupBy...  惰性（lazy）；\n",
      "  3) Action：collect/count/reduce/take...           立即触发；\n",
      "  4) DAG：转换构成有向无环图，Action 时提交执行；\n",
      "  5) 血缘（Lineage）：每个 RDD 记录父 RDD 与转换，故障自动重算；\n",
      "  6) Cache/Checkpoint：缓存中间结果，切断过长血缘。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print('''Spark 核心：\n",
    "  1) RDD：不可变、分区的数据集合（弹性=可重算、可缓存）；\n",
    "  2) Transformation：map/filter/flatMap/groupBy...  惰性（lazy）；\n",
    "  3) Action：collect/count/reduce/take...           立即触发；\n",
    "  4) DAG：转换构成有向无环图，Action 时提交执行；\n",
    "  5) 血缘（Lineage）：每个 RDD 记录父 RDD 与转换，故障自动重算；\n",
    "  6) Cache/Checkpoint：缓存中间结果，切断过长血缘。\n",
    "''')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd02-2",
   "metadata": {},
   "source": [
    "## 2️⃣ 手写迷你 RDD（简化版）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "bd02-mini",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:43:53.733407Z",
     "iopub.status.busy": "2026-10-08T09:43:53.731859Z",
     "iopub.status.idle": "2026-10-08T09:43:54.006372Z",
     "shell.execute_reply": "2026-10-08T09:43:53.992315Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "map 后血缘: ['source.map(<lambda>)', 'filter']\n",
      "➡️ 上面只是\"记录操作\"，没有真正执行任何计算（惰性）\n"
     ]
    }
   ],
   "source": [
    "class MiniRDD:\n",
    "    def __init__(self, partitions, deps=None, op=None):\n",
    "        self.partitions = partitions      # 分区列表（每区一个 list）\n",
    "        self.deps = deps or []            # 血缘\n",
    "        self.op = op or 'source'\n",
    "    def map(self, f):\n",
    "        # transformation：不执行，只记录闭包\n",
    "        new_parts = [None] * len(self.partitions)\n",
    "        return MiniRDD(new_parts, deps=self.deps + [f'source.map({f.__name__ if hasattr(f,\"__name__\") else \"lambda\"})'], op='map')\n",
    "    def filter(self, f):\n",
    "        return MiniRDD([None] * len(self.partitions), deps=self.deps + ['filter'], op='filter')\n",
    "    def materialize(self, f=None, g=None):\n",
    "        # 模拟执行：从源头开始真正计算\n",
    "        if self.op == 'source':\n",
    "            return [[x for x in p] for p in self.partitions]\n",
    "        # 简化：由闭包外部处理\n",
    "        return None\n",
    "\n",
    "src = MiniRDD([[1, 2, 3], [4, 5, 6], [7, 8, 9]])   # 3 个分区\n",
    "rdd2 = src.map(lambda x: x * 2).filter(lambda x: x > 5)\n",
    "print('map 后血缘:', rdd2.deps)\n",
    "print('➡️ 上面只是\"记录操作\"，没有真正执行任何计算（惰性）')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd02-3",
   "metadata": {},
   "source": [
    "## 3️⃣ 惰性求值演示：action 才触发"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "bd02-lazy",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:43:54.011087Z",
     "iopub.status.busy": "2026-10-08T09:43:54.010470Z",
     "iopub.status.idle": "2026-10-08T09:43:54.237114Z",
     "shell.execute_reply": "2026-10-08T09:43:54.215931Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "构建计划后：执行次数 = 0（尚未计算！）\n",
      "action(run) 后：执行次数 = 2，结果 = [[6], [8, 10, 12], [14, 16, 18]]\n",
      "✅ 惰性求值：transformations 不执行，action 才执行\n"
     ]
    }
   ],
   "source": [
    "# 完整迷你执行器：真正跑通 map/filter/count\n",
    "from functools import reduce\n",
    "\n",
    "class MiniSpark:\n",
    "    def __init__(self, partitions):\n",
    "        self._parts = partitions\n",
    "        self._plan = []          # (name, fn) 转换序列\n",
    "        self._executed = 0\n",
    "\n",
    "    def map(self, f):\n",
    "        self._plan.append(('map', f)); return self\n",
    "    def filter(self, f):\n",
    "        self._plan.append(('filter', f)); return self\n",
    "    def flatMap(self, f):\n",
    "        self._plan.append(('flatMap', f)); return self\n",
    "    def reduceByKey(self, f):\n",
    "        self._plan.append(('reduceByKey', f)); return self\n",
    "    def run(self):\n",
    "        parts = [list(p) for p in self._parts]\n",
    "        for name, fn in self._plan:\n",
    "            if name == 'map':\n",
    "                parts = [[fn(x) for x in p] for p in parts]\n",
    "            elif name == 'filter':\n",
    "                parts = [[x for x in p if fn(x)] for p in parts]\n",
    "            elif name == 'flatMap':\n",
    "                parts = [[y for x in p for y in fn(x)] for p in parts]\n",
    "            elif name == 'reduceByKey':\n",
    "                out = []\n",
    "                for p in parts:\n",
    "                    d = {}\n",
    "                    for k, v in p:\n",
    "                        d[k] = fn(d[k], v) if k in d else v\n",
    "                    out.append(list(d.items()))\n",
    "                parts = out\n",
    "            self._executed += 1\n",
    "        return parts\n",
    "\n",
    "ms = MiniSpark([[1, 2, 3], [4, 5, 6], [7, 8, 9]])\n",
    "ms.map(lambda x: x * 2).filter(lambda x: x > 5)\n",
    "print(f'构建计划后：执行次数 = {ms._executed}（尚未计算！）')\n",
    "res = ms.run()\n",
    "print(f'action(run) 后：执行次数 = {ms._executed}，结果 = {res}')\n",
    "# map 后 9 个元素，filter >5 保留 7 个\n",
    "assert ms._executed == 2 and sum(len(p) for p in res) == 7\n",
    "print('✅ 惰性求值：transformations 不执行，action 才执行')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "4b660458",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:43:54.241745Z",
     "iopub.status.busy": "2026-10-08T09:43:54.241081Z",
     "iopub.status.idle": "2026-10-08T09:43:55.592442Z",
     "shell.execute_reply": "2026-10-08T09:43:55.587003Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1kAAAFQCAYAAABNkbTSAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvctoD+AAAAAlwSFlzAAAPYQAAD2EBqD+naQAAbf1JREFUeJzt3XV0FNfjNvBns3H3ECQESHB3dwspHpxSCrRAkRaXlhYr0NIv7u7Bimtx1xAkQCBBQ0hCiLvtff/Iu/PLshujQ5E8n3P2QGbu3L0zmezus/fOHYUQQoCIiIiIiIhkofexG0BERERERPQlYcgiIiIiIiKSEUMWERERERGRjBiyiIiIiIiIZMSQRUREREREJCOGLCIiIiIiIhkxZBEREREREcmIIYuIiIiIiEhGDFlEX5ioqCgkJCRoLX/27BnS0tI+QouIiOhzplKpPnYTiD47DFlEX5hevXph/vz5WssHDx6M0aNH56mO+Ph4REZGvvf67KSlpSE0NBQZGRkAIP2bk/T09BzrokwpKSkQQnzsZhQIsbGxiIqKytc2KpXqk/r96PrQnNsH6cjISJ1f4AghkJqamuO2sbGxiImJyV8jKV8iIiJ0/n7+rR49emDcuHGy16uWlJT0QeqNi4vTec5FRUUhLi4uX3UxZNL70P/YDSCiDyc6OhrJyclITEzE2bNn0aNHj2yDiYWFBczMzAAAf/31F44dO4arV69K69PT06Gvn/mSMXPmTJw9e1ZjfV5cu3YNjRo1wsOHD1GoUCHUrVsX9evXx5QpU1CiRAmd2/Tq1QtlypTBzJkzddaVlJQEY2PjfLXjSxIZGYmBAwfi0KFDqFq1Kq5duwY9vc/7+7OMjAykpaX9579XlUqFN2/eaCwzNjaGtbW19HNycjIqV66Mxo0bY9OmTTrrCQ8Px5MnT/Ds2TP4+/vj1q1buHTpEry9vdG8eXNERERobWNtbS3tb1xc3L/6sGxrayv93b/L0tISz58/R9euXXHy5EkUKVJEWtetWzeUK1dO428tIyMDSqUSANClSxe0bdsWEydOhEqlks6zu3fvokaNGggMDISrq6vONo0fPx7JycnYsGEDhBAICwvLdT+MjIxgY2OTn13/qD7WeavWpk0beHl5YeLEiQAyv3jJ6csAPT09ODo65lpvxYoVMXv2bIwdOxbOzs65lg8KCkJiYiISEhIQHx+P6OhoREVFISoqCuHh4QgLC0NoaCiCg4Px/PlzJCQk4O7duyhbtmye91W9b46Ojtm+3k2aNAnR0dHYsmWLxvLu3bujQoUKWLBgQZ6eKy4uDnXq1MGcOXPQoUMHvHnzJsfQ9e5rBhVcDFlEXyiVSoUffvgBe/bskYYJDhs2DMOGDdNZfurUqdKbsy5DhgxBREQE9u7dK0v7rK2tce3aNUybNg0rV67EnDlztMokJyfj6NGj+O6777TCobonLSwsDEZGRhrrbG1tYWhoKEs71bJ+2PyUjBw5EsePH8eSJUsQGBiI1NTUzy50vntsW7dujdu3byMgIAC2trb/WTvevHmj9SGya9eu2L17t/TzvHnzkJycjJ07d2LKlClwd3fXqmfUqFHw9vZG0aJFUbp0aVSoUAFeXl6oXLkyfHx8UK9ePa1tvL290bNnTwDAlClTsHDhwvfejxMnTmD79u1Yu3at1rrFixfjhx9+gKOjI7y8vHDu3DkYGhpi79692LdvHwYNGiSVTU9PR7169dCmTRvMmDFDWh4aGoru3bujZs2amDdvHnx8fODq6pptwHpXREREnj6st2nTBseOHctTnR/Dp3LeZufgwYPo3r27ztdClUoFQ0NDxMfHAwBiYmKy7VHq0qULFi5ciOvXr6NOnTo6y9jY2MDIyAjp6elwcXHRWm9sbAwbGxvY2dnB3t4eDg4OaNiwIbp27QpnZ+d89/KeOHEC7du3R0hICAoVKpSvbdPT02FgYJDn8qNGjUJcXJz0d1u+fHmdX5SoeXp64tChQ/lqE32ZGLKIvhApKSnSG8fOnTtx8+ZN7Nu3D8HBwahYsSLmzZsHDw8Pndva29tLvVRZqb+tFkLg6NGj6NGjR67tiI+Pl96436UORm/fvpVC0/jx4wFA+tnKygomJiYAgP3798PGxgZ169aFlZWVzjp1fbA7ceIEWrZsmWtb8yI0NBTdunVD586d8zzc8r8ihMCePXvg5eWFwYMHf1LD0fIiKCgIPXv2RJ8+ffDDDz9Iy4sVK4bIyEjZg3Je3bp1CyVKlEDDhg1RpkwZafmdO3cwY8YM7N+/H3///TcGDx6MEydO6AzfQ4cOxZIlS7SWv3jxAkDmeaXerkKFChplxowZg759++psW1paGry8vGBkZIRt27bp/LstU6YMatSogalTp+LYsWP47bffcO3aNQCZ58ybN2/w119/YezYsQgMDISpqSlGjBiBYcOGoVq1aggNDZX+DpcvX44ZM2bg7du3Uv3Hjh2Du7u7FLxOnz6NRo0aaX0RYm5ujvT0dCQnJyMpKQnJyckIDQ2VhhYGBQWhaNGiOvdz5syZuHjxos51H9undt5GREQgLS0N6enpiI+PR2hoKExNTQEAxYsXx5UrV7S2uXz5Mvr16yf9PGzYMGzdujXH5+nUqVO26w4ePIivvvpK+nnevHno2LEjzM3NYWVlpfVF2IcUGRmJ1NRUJCYmSuecqakp0tPTkZqaiqSkJKSmpmqdr7p6xVavXo1Nmzbh3LlzcHBwAABcvXo122HsQOZ5TwQwZBF9MRYtWiSFmKZNm2LVqlXYvXs3Nm/ejMaNG2PUqFEYNWoU0tLSkJycDAsLC2nbs2fPomrVqhBCSMMgHj58iIYNG+LSpUvw9fXF69evUalSJYSGhiIhIUHnNVEODg6YOXMm/vjjjxzb2qhRo2zXLV++HEOGDAEArFy5El9//TUsLS0RHx+P8PBwqdzNmzfRrVs3+Pv7a7yBOzk5yfqG/vbtW1y8eBEdO3aUrU65vH37FklJSShWrBgAQKFQfOQW5U9YWBguX76MXr16aSzfsGHDx2nQ/2dhYYGYmBjcv38f27dvB5D5QbZ79+74/vvv0bp1a9SpUwe1atXCpEmT8Oeff2rVkZiYqPH3YWhoKA3jMzIygpOTk7Tu3d9bsWLFpN/pu6ZOnYqIiAhcuHABtWrVynE/bGxscP/+fbRr104KM02bNsW5c+ekMlkD3uLFi7F48WIAmR8ue/TogaJFi2LlypXIyMhAamoq4uPj0bZtW7Rt2xbp6enIyMjA0aNHERkZqfV7mzBhAvz9/bF//35p2c6dO/Hzzz8DyBxWqSskAsj2i5pPwad23rZo0QJ37twBkPlFwO+//47BgwejZcuWePHiBdzc3LS2ebcX7n//+x+mTp2qUSbrkNDclhcuXFjj52LFiqFkyZL53pekpKQ8XbsXHR0NABrvCUDml3Tt2rWTvlQAIH0h4ufnh0uXLgHIHG6+aNEijW3fvHkjBSkA2L17N4YNG4bly5dr9ODpOp5EOgki+iL8+OOPYv78+aJNmzZixowZYu7cuWL27NnC1NRUREZGSuU2b94sKlSooLMOPz8/4eTkJH799VdRunRp4eTkJLZt2yZ++uknASDXR0BAgIiJiRFBQUHixYsXIigoSOOxZ88eAUD8888/WuvUj/j4eCGEELdu3RIKhUIcPHhQCCFEQEBAntoQFxentV8ZGRkiKSkp38c0IiJCnD17VgAQv/76qwgJCZGOZVRUlAgLC5PKJiYmamyblpYmIiIiREZGhla9urZNSUnJth0qlUpERUUJlUolLYuOjhZ3794VAMRPP/0kQkJCRFRUlNa2qampIiIiQqSnp+usO7v9eHd5bGysVh0qlUrExMRk224hMo9DZGSkRtuFyDy2x44dEwDErFmzNNofGRmp8dzvSklJydc+JSQkiNTU1BzbKYQQISEh0nm8YMEC6e8kOjpa1KxZU7Rp00akpaVJ5R8+fChsbW3FpEmTNOrp06eP1nlZp04dIYQQ69atE25ubhrlnZychLe3d67tu3XrljAwMBBz587NtaxaqVKlxPHjx6WfExMTRVxcnIiLixOlS5cWa9asEdHR0QKAuH79urQuLS1NDBs2LMe/tR49eojdu3cLGxsbkZSUJD0KFSok5s+fL9LS0sTbt29FUFCQ6Nu3r+jWrZsICgoSz549y9Pfcps2bfK8n/mR3Tmpq9y759mneN6mpKSIpKQkUb16dTFjxgyRlJQk0tLSxK5du4Srq6sICQnRevz999/CzMws2zq9vb1FhQoVRGhoqMbybdu2iapVq4rnz5/r3C4tLU0AEKtXr9b5vDk94uPjxfr16/N0bmT3WL16tXjz5o0ICgoS/fv3F507dxZBQUEiKipKPH36VNy7d0+ULl1ajBw5Uty7d0/cu3dPbN26VQDQeJ9cs2aNMDIyEps2bRJCCDFs2DAxZMiQXH8XRFkxZBF9ITp06CC2bdsmhaw9e/YICwsL6YOA+rFkyRJRpkwZrTe45ORksX79etG0aVPx22+/iTp16ojdu3eLr776Spibm4sRI0aIqKgoERUVJX766SdRs2ZN6Wf1Qx0oVCqVaNWqlfjzzz812njhwgXpw8m73g0Z7du3FwC0Qtb9+/d1vkGrw5CukNWiRQthbW0tQkJC8nVMmzRpovUm3qJFCyGEEF27dhVmZmbizp07wtXVVRgYGIgHDx6IPXv2iJIlS0rljY2NhZeXl3jz5o1Ur3rbp0+fiubNmwsAwsDAQHh6emqUCwoKEr179xYmJiYCgDAzMxMLFy4UQgjRo0cPrbZ17dpV2vbUqVOiYcOGQqlUSu3o0qWL1oej7PbD09NT2NnZCV9fX1G1alUBQJiamorZs2cLIYSYN2+esLW1FQCEk5OT2Lx5s0a927dvF66urhrHoWfPniIiIkIIIUSdOnW02u/p6SmEEKJNmzbCzs5O6/dx/PhxUa9ePWmfTExMRPfu3UVQUJBGOXXbHz9+LBo3biwd344dO0rPr0vWkNWoUSPx+++/C39/f1GuXDnRunVrnUH93r17wtnZWXh4eIgnT54IITJD1rBhw3Q+R+vWrcWPP/6osaxUqVJi9OjR4tWrV+Lt27fZts3FxUWULFlSKJVKIYTQGeCzunbtmnBychLBwcEiJCREREdHa2xXpkwZsXnzZumD8b1794QQQisE3L9/X9SvX18AEBMmTNAIAo0aNRJ6enpSGEhNTRV6enri8OHDGnUMHjxYfPPNN0IIIcLDwwUAjd9bUlKSACAePnwohBBixowZsoes3M5JtatXr4qWLVsKAwMD6dyZMmWKEOLTPG/VatSoIf19ZmRkiF27dgmFQiGMjIy0HgYGBtmGrK1btwqlUikmTJigtS4iIkI0bdpUODo6iqtXr2qtV59L7/OYMWOGePv2rbhx40aOj549ewpDQ0MBQBw7dkxjXXh4uNSWYcOGiT59+gghNM9pNzc3MX/+fOnnK1euCAAaXxitWbNG7N27VwghxKVLl4Senp7YunWrePPmTZ4Co/pvjQo2Dhck+kIYGBhoXHBsYGCAOXPm4Pz58zpnbXp32datW3H27FnUrVtXWta1a1c8fvwYp06dws8//yzNmGRkZASlUpntDEoKhQKtW7fGuHHj4OjoiG+++UZj/YYNGzBp0iTp59OnT6N37944e/YsypYti+PHj+PkyZM6h/1Vr15d53OKHK5HsrGxgaWlZb4udgaABQsWwNfXFwMGDMCQIUPQo0cPrdnOBg4ciA4dOsDExARv375FbGws2rdvj/r168PJyQl+fn4YO3YsjI2NsXnzZmm79PR0dOnSBd27d8eoUaNw8OBBrFq1CqNGjcKWLVugUqnQunVrJCYmYt26dXBwcMC9e/ekawF+/fVXdO/eHV27dkXfvn0xcOBAaajL/v370aVLF7i7u2PZsmUoXLgwbt68iblz5+Lq1au4ffu2xrAYXfsBZA7d6devH0aMGAFbW1vMmTMHkyZNwoMHD3D16lUsWbIE6enp+PXXXzFgwAA0aNBAmiUyNjYWXbp0Qd26deHo6Ig7d+5g7NixMDc3x+rVq7Fs2TLcuHEDQ4YMwciRI9G5c2fY2dll+7vYuXMnevbsifLly2PFihUoVKgQrl27hr/++gvXrl2Dr6+vxu8mJSVFOjbjxo3Dnj17sH79eowfPx5r1qzJ9Xefnp6Ot2/fwtfXFy1atMCff/6J6OhoODk5ScP7kpKS4OTkBF9fXwwfPhxhYWE5DpGaM2cObty4gfXr12ss//rrrzF16lTMmzcPs2bN0vjbUD9Phw4dUKNGDTRq1Ajjxo1DWloa6tati5YtW2LatGk6JztZsmQJwsLCpBkEv/nmGyQmJqJ27doYO3aszja+ffsWZcqUwZkzZ2BjY4M//vgDa9euRc+ePREfH49du3Zh5cqVmDp1KlxcXBAYGAghBB49eoSKFSvC398fKpVK41q2d6mHJGcdLpiSkiI9f2hoKOLj45Gamoq4uDiNoc3/Rm7nJJB5PaenpyccHR0xd+5cuLu74+nTp9IQtk/9vH3y5Al69+6NBg0aoHDhwihXrhzu37+vVe78+fPo0qWL1vL58+dj/PjxmDNnjs5rUG1tbXHs2DEMHz4czZo1g7e3t86h1IsWLUKrVq1ybW9WDg4OsLOzy/F4nj59GgcPHsTUqVMxefJkVKlSJduJL5KTk3H79m00atQILVq0wJQpU6BUKhEVFaVxja/67znr0NWBAwcCyJzuvXfv3ujatSt69+4NV1dX6brKnHzzzTcffdgzfQI+dsojInmpe7LUwsPDc/3WTT1EbMCAAeLo0aNST5YQQhw5ckSr52nChAnS+pz07NlTGBgYiLNnzwoh/q8ny9jYWBw9elQIIcTly5dFkSJFNL4VrVatmpg9e7aws7PT6snK+k1lVvfu3cu2J+vfUNf77hCtrl27ai3X1bOQkpIiOnbsKOzt7bW23bZtm0bZWrVqCVNTUyGEEIGBgdJQwOyoe15+/vlnjTYULVpUFClSRMTGxmqU37t3r1b57PbD09NTANAYavb06VMBQBgaGkq9NkIIaRjo6tWrs21rcnKyaNOmjShatKi07MaNGwKAWLx4sUbZd3sEUlNThZOTk3B1dRUJCQkaZb29vaVvwdXUbd+zZ49G2UqVKglbW9ts25i1JyswMFCYmJgIHx8fjbZmHZK5evVqUbx4ca16+vTpI7799luNv7EXL16IVq1aiX379un8G7xz544ICAjQ2r+4uDjRqlUrUbt2bREXFyfmz58v9WRduXJFlCtXTpQpU0ZcunRJY7vnz58LAwMD0a1bN5GUlCR++ukn8c0334jp06eLRo0aCSF092QtW7ZMODo6irS0NDF06FAxbNgw8fDhQ5GWliY6d+4sFi9eLG7duiU8PDzEzJkzxebNm0X58uXFihUrhBBCrF27Vjg4OGi0JSMjQ/Tu3VuULFlSlCxZUhw4cCDPvRtjxozJ9vf1b717TmZkZIgSJUoIR0dHjR7ld31q560QQty8eVMUKVJEABDNmzcXZ86cyfMwvcTERJGYmCj69OkjzM3Nxe7du8WRI0dE5cqVtYYrHjlyRJQsWVKEhYWJX375RSiVSrF27VppvbpHcv/+/Tm29308fvxYODk5ieXLl4uDBw8KADpHJ4wePVq4uLgIAMLZ2Vn88ssv4ubNm6JUqVLiu+++EwqFQuN17dq1awKAVk91SkqKaNmypTSCQojM1+WHDx9qPQCIqVOnSj+/fv1a9v2nzw97soi+cA0bNsSTJ0+ynX48NTUV69atQ//+/aUpn7Pe/8rDwwO1a9fWuIhf18QXBgYGWt9AqutTX3T/+vVrAJmzp6lnJhsyZAj279+PGjVqSNsNGTIEAwYMwF9//aXV3jdv3uic2SmnKXU/pG+//Vb6v56eHlJSUrBy5UocP34c9+/fR1BQkPTNfWpqqjTzmJ6eHjp37qxRV+3atXHjxg1ERETA0dERxsbGWL58OdLT0zF48GBUrFgx1/b4+fnh1atX+Pnnn7V6ADp16gQrKyuNiQ+y2w8gc7KGrLM0lihRAlZWVihTpoxGj426Xa9evZKWJScnY/ny5fjnn3/w4MEDvHr1CiqV6r0m5/D19UVYWBhmzJghzZqm1qNHDwwYMADnzp3DL7/8Ii03NDRE+/btNcrWrl0ba9euRUJCgnRPuOyUKlUKXbt2xdKlS3VOhZ6b9evXa/RYtWjRAq6urjnO0Pbw4UON/YuIiEC7du2QnJyMs2fPas1aVrduXdy6dQsTJ05E48aNMXz4cMyaNQumpqaYMGEC0tLSoKenB2NjY+nvv2PHjpg2bVq2fy+bNm1Cr169oK+vj5kzZ0qzsbm7u2Ps2LHo2rUrAGDdunWws7ODgYEBLl68iH379mHw4ME4dOgQmjdvLtU3atQobNu2DW/evEGxYsUwfPhwqechPDxc2qeUlBRYW1vjzp07KF26tLR9dhNjvI/czsm7d+/i2bNn+OWXX7R6et/Hf3XefvXVVzh8+DD09PQwceJEzJ49G3Xr1tWY/CEny5cvh6enJ2JjY3H9+nWUK1cOwcHBePToEdasWYOhQ4dKZWfOnIkiRYrA0dERM2bMgLW1tcY9z5KTkwFkTtmekZGhNTGFLnm5X9fdu3fRunVr9OrVC0OGDMlxivTw8HAMHToUPj4+MDIykt5rjh49iiFDhkg9r61bt5ae/10pKSno1asXTp06BQDS63apUqWyfV4nJ6d83euLvnwMWUQFwF9//ZXt9Os5zfSnlnX2qqyy3uumSpUquH37tsZ6U1NTeHt7IyQkBN9++y02btwIAOjTpw9OnTqFjh074ubNm6hUqZLGdt9//322bXmf4YIfirGxsUawVKlUaNGiBS5dugSlUgk3Nze0bdsWz58/x4MHDzRuYGliYqI1xEv9gTMtLQ12dnZYuHAhRo4ciSVLlmDJkiVo1aoVVq1aleP9iNQfarLeZDYrJycnrdm73t0PNQsLC60PIOr73WSlnnJfHX7T09PRuHFj3LhxA/r6+nBzc4OHhwcCAwPx6NGjbNv+PvukUCjg4OCgtU8WFhZaH9CzHt+8qFSpkvRhTj3teF6n5x42bJjWFO7x8fFISEhAQkIC1q1bJy1fuHAh1q1bpzHc18fHBz179oSjo6M0dE8XY2NjLFiwAG3atEH//v1x6NAhbN68GaVKlUL37t117pONjQ0OHz6ste7atWu4evWqNHSuS5cuGoF8+PDhGD58uPTz1atXUadOHXTo0AEdO3bEjRs3cPToUXh7e0tl4uLi8OOPP+LGjRuwsrLC+PHj4ePjA1NTU9jb22u1wdDQ8IPc5y0v56T6S6DsboyeX//VeVu0aFGcOHECEydOlIbBXb16FSkpKYiJiZECTN++fWFubo4VK1borOfAgQPS/4sUKYKxY8di6tSp6NSpE5ydnbF161ZcuXJFY0r4MWPGaNShnvXPwsICz54903kfuXeZmZnlOJvk8ePH0atXL3z77bf43//+l2t96puEDx8+XGoPALi7u8PDwwOXL1/GpEmTsG/fPixdulR6jcvIyJBmXezbty/OnDmDuXPnZju0lig3um+TTURflEmTJqFs2bI6H0+fPs11+wsXLiAqKkp6/PTTT6hZs6bGsgsXLmhtl5ycjN9//x2lS5fG5cuXpTdkhUKBLVu2wNTUVGsa3dy8evUKycnJWg8fH5981SOHd3sHL126hEuXLqF3796IioqCv78/Dh8+jNq1a79X/d9//z0eP36MyZMnw83NDSdOnICXl1eO26inBn/y5InWuoyMDLx69Urr3kRy32T5zJkzuHHjBvr374/o6Gg8fPgQhw4dQrVq1d6rvpz2KTU1FSEhIdneb+l9REVF4fXr17h27ZrUAxEWFgZTU1OtHom8iI6OxvXr1xEVFYWxY8fi8OHDCAkJgb29PeLi4rBgwQLMnTtXqvt///sf6tevj2rVquHkyZN5urGth4cHbt++japVq8LBwQG///67zg+4CoUCvXr10vmlRFRUFPr16yf1TJ49exY+Pj4wNjbGrVu3IDIny8KOHTtgb28vlfPw8EDp0qXh4eGBQoUKwdPTU6pzzZo1mDx5ssaU9QEBAShatKg0zX1oaKjUG6K+Jis0NBSxsbH5OMo5y8s5qf6iIS+viXnxX523K1as0HlfwK1bt6J+/frvXe8vv/wCR0dHdO/eHQ8ePMCIESMwYsSIbG9IDGTeQwyAxnVShw8fxrNnz3Q+5s6dm21dSUlJGDFiBNq3b48JEybkKWDlRAiBTZs2oWvXrvD394eDgwMePXokfXGSmJiIKVOm4Mcff0Tz5s1x+vTpHPeVKDcMWUQFwOzZs+Hv76/zkZd7mVhYWMDa2lp6ZJ34Qv3IOjQtPT0dq1atgpubG5YvX4558+bh/v37GhdIlypVCps2bcK6deu0vg3NyZs3b6QPYVkfOQ0XjIuLQ3BwcJ6fIyt1L01UVBSAzDf+7Ki/Nf3qq6+k4xEdHY0TJ07k+3nVvV4uLi74/fff8fjxYzRs2BD37t3LcbsKFSrAzc0Na9as0bpAe/HixUhMTES3bt3y3Z78UB+HDh06SMObIiIicPr0aY1yeT221apVg4uLC1asWKH1e5w3bx7S0tJk3aeff/4ZRYoUwbFjxzBy5EgAmfdly8vfypYtW+Dn54d//vkHjRo1gpOTE2xsbNCoUSPcuHEDNWrUQO/eveHl5YV79+6hVatW6Ny5M3r37i3VER0djT///BM7d+6UjlFeODs7Y/fu3bnex2fRokVak9EAQNu2baXeZrWlS5fC0NAQPj4+yMjIwJs3bzB27FiMHz9e+t0qFAoMGDAAERER6NOnT64TzNy9exe1a9fGsmXL4OzsDGdnZ6l3tlGjRtIyXRMvxMXF4c2bNznWr0tezsnq1aujcOHCWL58uRQW1N7thQY+vfP2XYGBgVoTkKxcuRIKhUJ6NGzYMNvtjY2NsW/fPjx48ADVq1dH+fLldd4TLitfX1+Ymppq3OetcOHCcHV11fnQ1ZsJZE7eU7VqVRw4cABnz57FhAkT8rHnum3evBn37t3D8OHDUbRoUWzfvh0dO3aUXqvfvn2LwMBAJCQkYOjQoe/9pRCRGocLEhUAkyZNwm+//aZzXVxcnKzPdeDAAYwZMwZv3rzBxIkT8dNPP2X7QbF9+/bYunUrvv76a4SEhGDNmjW59hS8z3DB5s2b4+7duwgICNAYkpUXLi4usLOzw6pVq2BoaIjw8HCtYWBqdevWhZWVFcaOHYunT59CpVJhy5YtKFy4cL5D3t27d9G/f3+0a9cOzs7OCA4Ohq+vr84ZwbJSKBRYs2YNPDw8UKVKFfTt2xfOzs7w8fHB3r170alTJ50fsOXUoEEDmJub48cff4S/vz9SU1OxdetWFCtWTOMDcsmSJWFlZYWlS5dCpVIhKioKCxYs0KpPqVRizZo16NChAypVqoS+ffvCyckJ169fx4EDB9CjRw/07NlTtvb//vvvmD9/PooXLw5zc3OoVCr8/fff+Oqrr3Ld9tSpUwgNDUWxYsXQq1cvuLu7w83NDcWLF5eGJa1cuRK1atVC1apV0axZM42hgwCka0jkkJycjNDQUCQmJr7X9mvXrkWnTp3w22+/YcGCBTAwMECFChU0vhgJCAjAn3/+CWtrayxYsABeXl6oWrVqtnUePnwYw4YNQ2xsLJo0aYKzZ89qlRk+fLh0fU9WvXr1QkREhMaQtbzIyzlpYGCAVatWoXPnzqhYsSL69OmDYsWK4fHjxzAyMpKG2X2q5+27Tp06hfj4eCQlJUmvwd9++y3mzZsnlcnpmrfw8HD88ccfiIqKgo2NDRITE/HgwYMcw8fu3bvRpEmT976W7ty5c5g4cSJu3ryJIUOGYPr06TqHyqrPjbxe4/no0SOMGDEC33zzjcYMukBmr5uenh4ePXqEe/fuaVyDRvRvsCeLqABYtmwZoqOjdT5yGzMfHh6u1WuUdeKLrI+YmBikp6ejZcuWCAwMxKRJkzQCVtZvg9V69uyJPXv24MiRI6hWrZrGpBtqd+/ela732r9/P86ePav1UE8ycOPGDa3hObVr10aVKlU0pu3NKwMDA+zcuRNubm7YuXMnPDw8AGROC591CBSQOQXx8ePHUalSJaxZswanTp3CsmXL0LJlS42pv3VtC2T2GDo5OUGpVMLe3h7Ozs7YtWsX/ve//+HSpUuYNWuWRk+DUqmEk5OT1gQXTZo0gY+PDzp37oyTJ09i1apViIiIwIoVK/D3339rXGeVXVuyW+7o6Kg1fO3ddhQuXBhHjx5FmTJlsGrVKpw7dw5r1qxBkyZNNOo0MTHBjh074Orqit27d0vDzGxtbbWeu1WrVrh+/Trat2+P48ePY9WqVYiNjcWaNWvg7e2t8WEru7ZbWlrCyclJ54Xu7+57hQoVpGthVq1ahcDAQAwYMCDH7YDMCS9atmyJOnXq4IcffkCrVq1QokQJ6TljYmLw22+/ITAwEMWLF8fly5cxb948nZO5yGH//v1wdnbG8uXLAWT2vqj/XjMyMhATEyMN1YuIiJDWZf3ypXr16qhTpw78/f0RERGBFy9eYO/evRBC4PHjx2jdujWqVKmCp0+fonLlymjfvj3u3r2rsz0+Pj54/Pix1IOTmpqqs2daVygUQuDKlSs5Th6Snbyek56enrh27Ro8PT1x4sQJrF69Gs+ePdOYjvxTPW+zevr0KW7evAlzc3N06NBB6uk3NDTUGIHw7mQqAHD//n38+OOPcHV1xenTp7F37168evUKzZo1Q7169dCpUyecOnUKGRkZGtv5+fnh4sWLWtfUZj2vdL1nZBUTE4NChQrBz88PixcvlgLWiRMnMHDgQIwePRo///wzpkyZku21pM+ePcOLFy9w7949mJqawt/fHy1btkSpUqWwbNkyrfJGRkaoVq0axo0bB39//zxdp5yV+vYD7zOpD33hPtq8hkT0Qbw7hXuZMmXE+vXrNcqEhISIhw8fijt37ggTExOxc+dOjfVZp3B3cnLK83TLPXr00GpPUFCQCAgIEC9fvhQjRowQADRuZqr27Nkz0bFjRxEQECAtU0/h3qRJE+Hk5JTnx8iRI//NIaQCKusU7monT54UJiYmYsSIEVrlc5rC/d2bEfv5+YmRI0cKGxsbUaVKFXHmzBmhUqnEihUrhLW1tShevLiYOHGi8Pf3z7GNWadwz82cOXPE4MGDhRBCTJs2TYwcOVK0aNEiT3/Lw4YNE2vWrBEeHh7C0NBQ1K9fX9y4cUOkp6eLVatWiR49eoitW7cKCwsL0bFjR+k2EOHh4aJmzZrCxMREeHt7i6CgIPHs2TNRp04dMXToUNGgQQPx/fffCyGEmDt3rgAglEql1kOhUIiBAwdqHUMAuR6jgiYgIEA8ffpUFCtWTMybN08IIUSvXr1Eu3btRGxsrGjRooWwsbERLi4uwsPDQ5w+fVqcO3dOnDlzRhw7dkz4+fkJPz8/MW3aNFG9enUBQDRq1Ehs3bpV68bUz58/F0OHDhWWlpbC3t5e9O7dWyxatEiEh4dLtxpQqVRSu/JyrmV3U+SsTp8+Lezt7YWNjY2wtrYW7u7uYuPGjTrLdurUSQAQenp6Yt++feLOnTuia9euIjIyMtv6L1y4IMqVKyeGDBmitfzd1wQhhFi5cqWYNGmSmDVrlvDy8hIAtG7ATcThgkRfGFtbW41vJx0cHLSG6127dg2dOnWCQqFArVq10KZNG4315ubm0jeEjx8/1tkDpYuumdf27NmDH3/8Ufq5a9euOqfrdXV1xb59+zSWOTk5wdjYWOdwIiK5qXvksg51UigU6Natm8YQKzVTU1OdU31bW1vD0tJSY9muXbvw9u1b7N69G82aNZO+9R48eDB69+6N7du3Y8uWLbleo2NmZpbtzVfflfU6ll9//RVA5jCrvPSaGRoaYsKECXBzc8PUqVM1Jm/57rvvMGjQIIwYMQLTpk3DqFGjpHX29va4ePEifvzxRxQuXBiTJ0/G5s2boa+vjylTpiAtLQ2zZ8+W9qVz587Ys2eP1vNPnjxZ6iFQu3jxIsqVK5fjjY4LIi8vL9y5cwdGRkZo1qwZ1q9fj927d+PSpUuwsLDAiRMnsH//fuzcuRMBAQEYNGiQNJNeRkYGFixYADs7Oxw/fhzdu3fHjh07sr2ur3jx4li2bBn++usv7N+/H4cOHcL58+cxdOhQ1K9fH507d9a4ua+TkxP+/vvvbH9n+/fvx6xZs3Ldx2bNmuVpOngAWL16Nf744w9YW1tL7zW7d+/OcZuGDRviwYMHWssNDQ21XhMA4MWLF1izZg2EEDA2NsbAgQO13keJFEJ8hHmPieijUw/1kHtmuXdFRETAz88PGRkZsLe3R+XKlT/o8xHRpyM4OFiaRS+v4TA7d+/eRWpqKmrWrClT674Mz549Q3JyMpydnWFtbY3ly5cjKSlJ58QhRPTfYcgiIiIiIiKSESe+ICIiIiIikhFDFhERERERkYwYsoiIiIiIiGTE2QUpRyqVCq9fv4aFhQXvAUFEREREXwQhBOLi4lC4cOF83YcurxiyKEevX79GsWLFPnYziIiIiIhkFxQUhKJFi8peL0MW5cjCwgJA5gn47n1fiIiIiIg+R7GxsShWrJj0WVduDFmUI/UQQUtLS4YsIiIiIvqifKjLYTjxBRERERERkYwYsoiIiIiIiGTEkEVERERERCQjhiwiIiIiIiIZMWQRERERERHJiCGLiIiIiIhIRgxZREREREREMmLIIiIiIiIikhFvRkx5ctHKCmYfuxGfkCZCfOwmEBEREdEnij1ZREREREREMmLIIiIiIiIikhFDFhERERERkYwYsoiIiIiIiGTEkEVERERERCQjhiwiIiIiIiIZMWQRERERERHJiCGLiIiIiIhIRgxZREREREREMmLIIiIiIiIikhFDFhERERERkYwYsoiIiIiIiGTEkEVERERERCQjhiwiIiIiIiIZMWQRERERERHJiCGLiIiIiIhIRgxZREREREREMmLIIiIiIiIikhFDFhERERERkYwYsoiIiIiIiGTEkEVERERERCQjhiwiIiIiIiIZMWQRERERERHJiCGLiIiIiIhIRgxZREREREREMmLIIiIiIiIikhFDFhERERERkYwYsoiIiIiIiGTEkJUHsbGxEEJ8sPqfP3+O2NjYD1Y/AAQGBiIhIeGDPgcRERERETFk6ZQ1jGRkZMDFxQUzZsz4IM918eJFNGrUCOnp6R+kfrXNmzejV69eH/Q5iIiIiIiIIUvLkiVLULt2belnpVKJRYsWoWfPnrI/l0qlwoABA/C///0Ptra2stef1ZQpU/Do0SPs2LHjgz4PEREREVFB98WGLJVKhdevX+c4DC8hIQEvXryQepFevHgBf39/JCUlwd/fH69evQIA1K9fH46Ojlrbx8XF4enTp0hMTNRaFxgYiOjoaABASEgI4uLitMrs3bsXKpUKXl5eWtulp6fjwYMHSEhIgL+/v9Zz+Pv7a9SZ2/Pp6+tjzJgxmDNnTrbHg4iIiIiI/r0vMmTNmzcPtra2KFmyJKytrdG5c2ekpaVJ6+Pi4tCvXz/Y2NigZMmSKFy4MO7evYuvv/4aq1atwvPnz1GzZk2MGDECAFC3bl1s2bJF2j48PBydOnWCtbU13N3dYWNjg+HDh2s8R8OGDbFw4UI0a9YMRYsWhZWVFX766SeNdu7evRteXl7Q09PT2G7BggWoWLEiKlSogEePHqFcuXK4fPmyVCY9PR3lypXD8ePH8/V8Xl5euHv3Lp4+ffqvji8REREREWXviwxZ6enpOHfuHBITE3H//n0cP35cIyT16tULFy9exLlz55CSkgJvb28kJCTg/PnzmDx5MkqXLo34+Hjs3btXZ/2dOnXCixcv4Ofnh9TUVBw+fBhbt27FvHnzNMotXrwYkydPRkpKCubNm4eFCxfi+vXr0voLFy6gcePGWvWvWrUKU6dOxdu3b1G8ePE873duz2dra4sKFSrgwoUL2daRkpKC2NhYjQcREREREeXdFxmyxo8fjypVqkBPTw+Ojo4oW7Ys7ty5AwC4c+cODh8+jFWrVqFevXrQ19dHixYtUK9evTzVfeXKFVy+fBkrVqxAuXLloFQq0bJlS/z4449YtGiRRtmePXuiVatW0NfXx4gRI2BmZoabN28CAIQQCA0NRbFixbSeo2nTpujZsyfs7OygVCrzvN85PZ9a0aJFERwcnG0ds2fPhpWVlfTQ1T4iIiIiIsreFxmyjhw5gtatW8Pa2hpubm549OgR4uPjAQC3bt2Cnp6ezh6kvLh//z6USiVq1KihsbxatWp4/fq1xsyEpUuXlv6vVCrh5OSEqKgoAEBiYiIyMjJgbm6u9RzVqlV7r7bl9HxqFhYW0rHQZdKkSYiJiZEeQUFB79UWIiIiIqKC6osLWbdv30aHDh3QpUsXPHnyBFFRURq9VCYmJhBCvPeU6VZWVlCpVEhNTdVYnpiYCIVCoXF9Vdb/A4BCoZDut2VmZgYDAwOtEKRuo5q+vj4AaFzvlZKSorNtOT2fWmRkJGxsbLLdPyMjI1haWmo8iIiIiIgo7764kHXx4kXY2tpiyJAhsLOzQ2JiIu7duyetr1GjBhQKBfbt26exnTp06evrawSad2W3/fHjx1GrVi2NgJSbEiVKIDAwMMcy5ubmsLCwwMOHD6VlFy9ezPNzvCswMBAlSpR47+2JiIiIiChn+h+7AXIrV64cwsPDMX36dFStWhXLly+XeoMAwN3dHUOGDMH333+Pp0+fokKFCjh+/DjatWuHDh06oEyZMnj+/DnWr18PNzc3NGrUSKP+kiVLYvjw4fj+++/x4sULlCtXDqdPn8aOHTtw7NixfLW1WbNmOH36NLp3755juQ4dOkjXSimVSqxYsSJfz6P27NkzvHjxAk2bNn2v7YmIiIiIKHdfXMhq0aIFFi1ahG3btuHEiRMYM2YMDh8+jEKFCkllFi1aBHd3d/z99984cOAAmjVrhmbNmgEAOnfujOHDh2PhwoVo3rw5GjVqJE3TrjZ//ny4u7tj165d8Pb2RtmyZXHhwgXUrFlTKvPuNgBQqlQp2NvbSz/3798fHh4e+Ouvv6Rrs3Rtt3TpUkyaNAnLli2Di4sL1q5di65du2oM5cvL861ZswZfffWVxjIiIiIiIpKXQrx70Q79pzw8PNCgQQP88ssvH/R53rx5gwoVKuDo0aMaYTA3sbGxsLKywmEAZh+ueZ+dJvyzISIiIvpsqT/jxsTEfJA5CL64a7I+N+vWrcOhQ4fw8uXLD/o8c+fOxfjx4/MVsIiIiIiIKP/Yk0U5Yk+WbuzJIiIiIvp8sSeLiIiIiIjoM8KQRUREREREJCOGLCIiIiIiIhkxZBEREREREcmIIYuIiIiIiEhGDFlEREREREQyYsgiIiIiIiKSEUMWERERERGRjBiyiIiIiIiIZMSQRUREREREJCOGLCIiIiIiIhkxZBEREREREcmIIYuIiIiIiEhGDFlEREREREQyYsgiIiIiIiKSEUMWERERERGRjBiyiIiIiIiIZMSQRUREREREJCOGLCIiIiIiIhkxZBEREREREcmIIYuIiIiIiEhGDFlEREREREQyYsgiIiIiIiKSEUMWERERERGRjBiyiIiIiIiIZMSQRUREREREJCP9j90A+jw0jImBpaXlx24GEREREdEnjz1ZREREREREMmLIIiIiIiIikhFDFhERERERkYwYsoiIiIiIiGTEkEVERERERCQjhiwiIiIiIiIZMWQRERERERHJiCGLiIiIiIhIRgxZREREREREMmLIIiIiIiIikhFDFhERERERkYwYsoiIiIiIiGTEkEVERERERCQjhiwiIiIiIiIZMWQRERERERHJiCGLiIiIiIhIRgxZREREREREMmLIIiIiIiIikhFDFhERERERkYwYsoiIiIiIiGTEkEVERERERCQjhiwiIiIiIiIZMWQRERERERHJiCGLiIiIiIhIRgxZREREREREMmLIIiIiIiIikhFDFhERERERkYwYsoiIiIiIiGTEkEVERERERCQjhiwiIiIiIiIZMWQRERERERHJiCGLiIiIiIhIRgxZREREREREMmLIIiIiIiIikhFDFhERERERkYwYsoiIiIiIiGTEkEVERERERCQjhiwiIiIiIiIZMWQRERERERHJiCGLiIiIiIhIRgxZREREREREMmLIIiIiIiIikhFDFhERERERkYwYsoiIiIiIiGTEkEVERERERCQjhiwiIiIiIiIZMWQRERERERHJiCGLiIiIiIhIRgxZREREREREMmLIIiIiIiIikhFDFhERERERkYwYsoiIiIiIiGTEkEVERERERCQjhiwiIiIiIiIZMWQRERERERHJiCGLiIiIiIhIRgxZREREREREMmLIIiIiIiIikhFDFhERERERkYwYsoiIiIiIiGTEkEVERERERCQjhiwiIiIiIiIZMWQRERERERHJiCGLiIiIiIhIRgxZREREREREMmLIIiIiIiIikhFDFhERERERkYwYsoiIiIiIiGTEkEVERERERCQjhiwiIiIiIiIZMWQRERERERHJiCGLiIiIiIhIRgxZREREREREMmLIIiIiIiIikhFDFhERERERkYwYsoiIiIiIiGTEkEVERERERCQjhiwiIiIiIiIZMWQRERERERHJiCGLiIiIiIhIRgxZREREREREMmLIIiIiIiIikhFDFhERERERkYwYsoiIiIiIiGSk/7EbQJ+H2bNnw8jI6GM3g4iIiIjyaerUqR+7CQUOe7KIiIiIiIhkxJBFREREREQkI4YsIiIiIiIiGTFkERERERERyYghi4iIiIiISEYMWURERERERDJiyCIiIiIiIpIRQxYREREREZGMGLKIiIiIiIhkxJBFREREREQkI4YsIiIiIiIiGTFkERERERERyYghi4iIiIiISEYMWURERERERDJiyCIiIiIiIpIRQxYREREREZGMGLKIiIiIiIhkxJBFREREREQkI4YsIiIiIiIiGTFkERERERERyYghi4iIiIiISEYMWURERERERDJiyCIiIiIiIpIRQxYREREREZGMGLKIiIiIiIhkpP+xG0BERLnT09ODvn7eXrLT09OhUql0rlMoFDAwMMhx+7S0NAghAABKpRJKpTLX5xRCIC0tLU/t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",
      "text/plain": [
       "<Figure size 900x320 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "run 前 _executed 应为 0，run 后为 2 -> 验证：构建计划时 executed = 0\n"
     ]
    }
   ],
   "source": [
    "# 可视化：惰性求值时间线（构建期 vs action 期）\n",
    "fig, ax = plt.subplots(figsize=(9, 3.2))\n",
    "ax.barh(['构建 map/filter 链', 'action(run)'], [1.8, 0.2], color=['#7F7F7F', '#C00000'], height=0.45)\n",
    "ax.text(0.9, 0, '只记录转换，0 次数据遍历', ha='center', va='center', color='white', fontsize=11)\n",
    "ax.text(0.9, 1, '0 次遍历', ha='center', va='center', color='white', fontsize=10)\n",
    "ax.set_xlim(0, 2); ax.set_xlabel('时间 →', fontsize=11); ax.set_yticks([0, 1])\n",
    "ax.set_title('惰性求值：transformation 阶段不碰数据，action 提交后才执行', fontsize=12)\n",
    "plt.show()\n",
    "# 关键证据：ms._executed 在 run() 前后分别为 0→2（map、filter 各执行 1 轮）\n",
    "print('run 前 _executed 应为 0，run 后为 2 ->', '验证：构建计划时 executed =', MiniSpark([[1]])._executed)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd02-4",
   "metadata": {},
   "source": [
    "## 4️⃣ 词频（Spark 风格）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "bd02-wc",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:43:55.598096Z",
     "iopub.status.busy": "2026-10-08T09:43:55.597095Z",
     "iopub.status.idle": "2026-10-08T09:43:55.633190Z",
     "shell.execute_reply": "2026-10-08T09:43:55.631280Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Spark 风格词频: {'apple': 3, 'banana': 2, 'cherry': 2}\n",
      "✅ 词频统计与手写 MapReduce 结果一致\n"
     ]
    }
   ],
   "source": [
    "lines = ['apple banana', 'apple cherry', 'banana cherry apple']\n",
    "ms2 = MiniSpark([[w for line in lines for w in line.split()]])\n",
    "ms2.map(lambda w: (w, 1)).reduceByKey(lambda a, b: a + b)\n",
    "out = ms2.run()\n",
    "wc = dict(out[0])\n",
    "print('Spark 风格词频:', wc)\n",
    "assert wc['apple'] == 3 and wc['cherry'] == 2 and wc['banana'] == 2\n",
    "print('✅ 词频统计与手写 MapReduce 结果一致')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd02-5",
   "metadata": {},
   "source": [
    "## 5️⃣ 宽窄依赖与 Shuffle（图示）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "e0edb780",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:43:55.637270Z",
     "iopub.status.busy": "2026-10-08T09:43:55.636672Z",
     "iopub.status.idle": "2026-10-08T09:43:56.531731Z",
     "shell.execute_reply": "2026-10-08T09:43:56.510122Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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gsoQ++WXEEkkSJg7F3kJCWh/+DAcfcpevvnc009D0bgxMrZuReqGDQj8/Xe4l7G8Y3WQsmYNTk+ahOCDB6FsWrFLOVcH2efP42BwMJrOmQOPUbdfTY3qDo5AIKIap6FnYyx6dZe9w6g0CkcVvn9qjb3DICKiGkzVpg3OPfEExEolAlesqJLkAQAoAwNxevx4KFu2RJuIiHIlDwBA06EDzj/zDGSurmg8e3aNSB4AgNvQoehsNts7jEqjaNwYnW8pCkp1G0cgEBEREREREVGZ7m4CDBERERERERHVSUwgEBEREREREVGZmEAgIiIiIiIiojIxgUBEREREREREZWICgYiIiIiIiIjKxAQCEREREREREZWJCQQiIiIiIiIiKhMTCERERERERERUJiYQiIiIiIiIiKhMTCAQERERERERUZmYQCAiIiIiIiKiMjGBQERERERERERlYgKBiIiIiIiIiMrEBAIRERERERERlYkJBCIiIiIiIiIqExMIRERERERERFQmJhCIiIiIiIiIqExMIBARERERERFRmZhAICIiIiIiIqIyMYFARERERERERGViAoGIiIiIiIiIysQEAhERERERERGViQkEIiIiIiIiIioTEwhEREREREREVCYmEIiIiIiIiIioTEwgEBEREREREVGZmEAgIiIiIiIiojIxgUBEREREREREZWICgYiIiIiIiIjKxAQCEREREREREZWJCQQiIiIiIiIiKhMTCERERERERERUJiYQiIiIiIiIiKhMTCAQERERERERUZmYQCAiIiIiIiKiMjGBQERERERERERlYgKBiIiIiIiIiMrEBAIRERERERERlYkJBCIiIiIiIiIqExMIRERERERERFQmJhCIiIiIiIiIqExMIBARERERERFRmZhAICIiIiIiIqIyMYFARERERERERGWS2juAqhafYkaGKcfeYdA9cNLK4e2msXcYRBUm2ZgAsyXD3mHQXdIoneCu87J3GFRB2C+omdgnoNqGfYKaq671C+pUAiE+xYyhzy1HTl6BvUOheyB3kGLNrNHsMFCtkGxMwHM/jkJePh9cahoHmRyzHl9RpzoLtRX7BTUX+wRUm7BPULPVtX5BnUogZJhykJNXgKfH6VHPU2vvcOguxCWa8N0SAzJMOewsUK1gtmQgLz8H4x94Ap7OPvYOh8opMf06Fv/9A8yWjDrT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",
      "text/plain": [
       "<Figure size 1050x400 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 可视化：宽依赖 vs 窄依赖（分区连线）\n",
    "fig, axes = plt.subplots(1, 2, figsize=(10.5, 4))\n",
    "for ax, title, wide in zip(axes, ['窄依赖: map/filter（一对一）', '宽依赖: reduceByKey/join（多对多）'], [False, True]):\n",
    "    ax.set_xlim(0, 10); ax.set_ylim(0, 10); ax.axis('off')\n",
    "    ax.set_title(title, fontsize=12, color=('#C00000' if wide else '#548235'))\n",
    "    for i in range(3):\n",
    "        ax.add_patch(plt.Rectangle((1, 7.2 - i * 2.4), 2.2, 1.6, fc='#D9E2F3', ec='#2F5597'))\n",
    "        ax.add_patch(plt.Rectangle((6.8, 7.2 - i * 2.4), 2.2, 1.6, fc='#E2EFDA', ec='#548235'))\n",
    "        ax.text(2.1, 8 - i * 2.4, f'父P{i}', ha='center', va='center', fontsize=9)\n",
    "        ax.text(7.9, 8 - i * 2.4, f'子P{i}', ha='center', va='center', fontsize=9)\n",
    "    if wide:\n",
    "        for i in range(3):\n",
    "            for j in range(3):\n",
    "                ax.plot([3.2, 6.8], [8 - i * 2.4, 8 - j * 2.4], color='#C00000', lw=0.8, alpha=0.5)\n",
    "    else:\n",
    "        for i in range(3):\n",
    "            ax.plot([3.2, 6.8], [8 - i * 2.4, 8 - i * 2.4], color='#548235', lw=1.8)\n",
    "plt.tight_layout(); plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "bd02-dep",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:43:56.539943Z",
     "iopub.status.busy": "2026-10-08T09:43:56.537086Z",
     "iopub.status.idle": "2026-10-08T09:43:56.588447Z",
     "shell.execute_reply": "2026-10-08T09:43:56.584718Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "窄依赖（Narrow）：父分区只被子分区之一使用\n",
      "  map/filter/flatMap/union -> 无需 Shuffle，可流水线\n",
      "  宽依赖（Wide）  ：父分区被多个子分区使用\n",
      "  groupByKey/reduceByKey/join -> 需要 Shuffle（数据跨节点传输）\n",
      "\n",
      "优化面试点：\n",
      "  1) reduceByKey 优于 groupByKey（map 端预聚合）；\n",
      "  2) Shuffle 是性能瓶颈 -> 控制分区数、避免过多 Shuffle；\n",
      "  3) 血缘长 -> checkpoint 截断（故障恢复更快）。\n",
      "\n",
      "分区内预聚合（combine）:\n",
      "  分区0: [('a', 1), ('b', 1)] -> [('a', 1), ('b', 1)]\n",
      "  分区1: [('a', 1), ('a', 1)] -> [('a', 2)]\n",
      "  分区2: [('b', 1), ('c', 1)] -> [('b', 1), ('c', 1)]\n"
     ]
    }
   ],
   "source": [
    "print('''窄依赖（Narrow）：父分区只被子分区之一使用\n",
    "  map/filter/flatMap/union -> 无需 Shuffle，可流水线\n",
    "  宽依赖（Wide）  ：父分区被多个子分区使用\n",
    "  groupByKey/reduceByKey/join -> 需要 Shuffle（数据跨节点传输）\n",
    "\n",
    "优化面试点：\n",
    "  1) reduceByKey 优于 groupByKey（map 端预聚合）；\n",
    "  2) Shuffle 是性能瓶颈 -> 控制分区数、避免过多 Shuffle；\n",
    "  3) 血缘长 -> checkpoint 截断（故障恢复更快）。\n",
    "''')\n",
    "# 演示：reduceByKey 的 map 端预聚合\n",
    "partitions = [[('a', 1), ('b', 1)], [('a', 1), ('a', 1)], [('b', 1), ('c', 1)]]\n",
    "print('分区内预聚合（combine）:')\n",
    "for i, p in enumerate(partitions):\n",
    "    d = {}\n",
    "    for k, v in p:\n",
    "        d[k] = d.get(k, 0) + v\n",
    "    print(f'  分区{i}: {p} -> {list(d.items())}')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd02-6",
   "metadata": {},
   "source": [
    "## 6️⃣ Cache 与血缘（面试速答）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "bd02-cache",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:43:56.635395Z",
     "iopub.status.busy": "2026-10-08T09:43:56.620577Z",
     "iopub.status.idle": "2026-10-08T09:43:56.844534Z",
     "shell.execute_reply": "2026-10-08T09:43:56.813883Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1) cache():    把中间 RDD 存内存，避免反复从源头重算；\n",
      "2) checkpoint: 写到可靠存储，切断血缘（适合血缘超长）；\n",
      "3) 缓存 vs 检查点：缓存可能丢失（依赖血缘可重算），检查点直接切断；\n",
      "4) 何时用 cache？-> 同一 RDD 被多次 action / 迭代计算；\n",
      "5) cache 是 lazy 的：真正缓存发生在第一次 action 后。\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "print('''1) cache():    把中间 RDD 存内存，避免反复从源头重算；\n",
    "2) checkpoint: 写到可靠存储，切断血缘（适合血缘超长）；\n",
    "3) 缓存 vs 检查点：缓存可能丢失（依赖血缘可重算），检查点直接切断；\n",
    "4) 何时用 cache？-> 同一 RDD 被多次 action / 迭代计算；\n",
    "5) cache 是 lazy 的：真正缓存发生在第一次 action 后。\n",
    "''')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd02-7",
   "metadata": {},
   "source": [
    "## 7️⃣ DataFrame vs RDD（面试对比）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "bd02-df",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-08T09:43:56.873687Z",
     "iopub.status.busy": "2026-10-08T09:43:56.848080Z",
     "iopub.status.idle": "2026-10-08T09:43:57.111161Z",
     "shell.execute_reply": "2026-10-08T09:43:57.098596Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "| 维度 | RDD | DataFrame |\n",
      "|---|---|---|\n",
      "| 抽象 | 无结构数据+函数 | 有 schema 的表 |\n",
      "| 优化 | 靠手写 | Catalyst 优化器自动 |\n",
      "| 类型安全 | 弱（运行时） | 有（编译期 schema） |\n",
      "| 易用性 | 低 | 高（SQL 语法） |\n",
      "| 现状 | 底层引擎 | 生产主力（Spark SQL） |\n",
      "\n",
      "Spark SQL 三大优势：Catalyst 优化、Tungsten 内存管理、DataSource API。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print('''| 维度 | RDD | DataFrame |\n",
    "|---|---|---|\n",
    "| 抽象 | 无结构数据+函数 | 有 schema 的表 |\n",
    "| 优化 | 靠手写 | Catalyst 优化器自动 |\n",
    "| 类型安全 | 弱（运行时） | 有（编译期 schema） |\n",
    "| 易用性 | 低 | 高（SQL 语法） |\n",
    "| 现状 | 底层引擎 | 生产主力（Spark SQL） |\n",
    "\n",
    "Spark SQL 三大优势：Catalyst 优化、Tungsten 内存管理、DataSource API。\n",
    "''')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8a387e44",
   "metadata": {},
   "source": [
    "### 执行流程与分区数设置（面试展开）\n",
    "\n",
    "**spark-submit 之后发生了什么**：\n",
    "Driver 启动 → 解析代码构建 DAG → 遇到 **Action** 触发 **Job** → DAGScheduler 按**宽依赖**切 Stage\n",
    "→ 每个 Stage 生成一批 **Task**（1 分区 = 1 Task）→ TaskScheduler 把 Task 派发给 **Executor** 执行\n",
    "→ 结果回传 Driver。\n",
    "\n",
    "**分区数怎么定**（经验法则）：\n",
    "- 下限：≥ 总核心数（吃满并行度）；\n",
    "- 经验值：**总核心数的 2~3 倍**（让任务不均时忙核可接活，避免长尾）；\n",
    "- 太少：并行不足、单任务内存压力大；太多：调度开销、小文件（写出的文件数≈分区数）。\n",
    "\n",
    "**Shuffle 分区数**由 `spark.sql.shuffle.partitions`（默认 200）控制，小数据调小、大数据调大。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd02-8",
   "metadata": {},
   "source": [
    "## 📝 自测清单\n",
    "\n",
    "- [ ] 能解释 RDD/Transformation/Action/DAG 四概念\n",
    "- [ ] 能演示惰性求值（action 触发）\n",
    "- [ ] 能讲清宽窄依赖与 Shuffle\n",
    "- [ ] 能解释血缘与 cache/checkpoint 的区别\n",
    "- [ ] 能对比 RDD 与 DataFrame"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
