#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
// --- GEOMETRIC STRUCTURES ---
struct Rectangle {
int id;
double minX, minY, maxX, maxY;
// Helper to check intersection between two rectangles
bool intersects(const Rectangle& other) const {
return !(minX > other.maxX || maxX < other.minX ||
minY > other.maxY || maxY < other.minY);
}
};
// --- PROVIDED TREE LIBRARY (Simulated) ---
class GeoTree {
private:
// In a real library, this would be a pointer to an R-Tree or Quad-Tree structure
vector<Rectangle> treeData;
public:
// Requirement: Add operation takes O(log n)
void addRectangle(int id, Rectangle r) {
r.id = id;
treeData.push_back(r);
// Note: In a real R-Tree, this would involve rebalancing the tree nodes.
}
// Requirement: Query operation takes O(log n)
vector<int> queryRectangle(Rectangle q) {
vector<int> results;
// In a real tree library, this traverses only relevant branches
for (const auto& rect : treeData) {
if (rect.intersects(q)) {
results.push_back(rect.id);
}
}
return results;
}
};
// --- MAP-REDUCE LOGIC (Case 1: Map-Only Join) ---
/**
* @brief Performs a Spatial Join using the Broadcast strategy.
* * Case 1: Table A is small enough to fit in memory.
* We build the spatial index (Tree) once and then stream Table B.
*/
void broadcastSpatialJoin(const vector<Rectangle>& smallTableA,
const vector<Rectangle>& largeTableBPartition) {
// 1. INITIALIZE the Tree
GeoTree spatialIndex;
// 2. BROADCAST PHASE: Build the tree from the small table (e.g., Cities)
// This happens once per Mapper worker.
for (const auto& city : smallTableA) {
spatialIndex.addRectangle(city.id, city);
}
// 3. MAP PHASE: Stream the large table (e.g., Uber Trips)
// We check each trip against the indexed cities.
cout << "--- Spatial Join Results ---" << endl;
cout << "CityID\tTripID" << endl;
for (const auto& trip : largeTableBPartition) {
// Query returns all City IDs that the current trip intersects
vector<int> matchingCityIds = spatialIndex.queryRectangle(trip);
for (int cityId : matchingCityIds) {
// "Emit" the join result
cout << cityId << "\t" << trip.id << endl;
}
}
}
// --- MAIN EXECUTION ---
int main() {
// Dataset A: Small Table (e.g., City Boundaries)
// Format: {ID, minX, minY, maxX, maxY}
vector<Rectangle> cities = {
{1, 0.0, 0.0, 5.0, 5.0}, // City A
{2, 10.0, 10.0, 15.0, 15.0} // City B
};
// Dataset B: Large Table Partition (e.g., Uber Trips)
vector<Rectangle> trips = {
{101, 2.0, 2.0, 3.0, 3.0}, // Inside City A
{102, 4.0, 4.0, 6.0, 6.0}, // Intersects City A
{103, 12.0, 12.0, 18.0, 18.0}, // Intersects City B
{104, 20.0, 20.0, 25.0, 25.0} // Matches nothing
};
// Run the distributed join simulation
broadcastSpatialJoin(cities, trips);
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dmVjdG9yPgojaW5jbHVkZSA8c3RyaW5nPgojaW5jbHVkZSA8YWxnb3JpdGhtPgoKdXNpbmcgbmFtZXNwYWNlIHN0ZDsKCi8vIC0tLSBHRU9NRVRSSUMgU1RSVUNUVVJFUyAtLS0KCnN0cnVjdCBSZWN0YW5nbGUgewogICAgaW50IGlkOwogICAgZG91YmxlIG1pblgsIG1pblksIG1heFgsIG1heFk7CgogICAgLy8gSGVscGVyIHRvIGNoZWNrIGludGVyc2VjdGlvbiBiZXR3ZWVuIHR3byByZWN0YW5nbGVzCiAgICBib29sIGludGVyc2VjdHMoY29uc3QgUmVjdGFuZ2xlJiBvdGhlcikgY29uc3QgewogICAgICAgIHJldHVybiAhKG1pblggPiBvdGhlci5tYXhYIHx8IG1heFggPCBvdGhlci5taW5YIHx8IAogICAgICAgICAgICAgICAgIG1pblkgPiBvdGhlci5tYXhZIHx8IG1heFkgPCBvdGhlci5taW5ZKTsKICAgIH0KfTsKCi8vIC0tLSBQUk9WSURFRCBUUkVFIExJQlJBUlkgKFNpbXVsYXRlZCkgLS0tCgpjbGFzcyBHZW9UcmVlIHsKcHJpdmF0ZToKICAgIC8vIEluIGEgcmVhbCBsaWJyYXJ5LCB0aGlzIHdvdWxkIGJlIGEgcG9pbnRlciB0byBhbiBSLVRyZWUgb3IgUXVhZC1UcmVlIHN0cnVjdHVyZQogICAgdmVjdG9yPFJlY3RhbmdsZT4gdHJlZURhdGE7CgpwdWJsaWM6CiAgICAvLyBSZXF1aXJlbWVudDogQWRkIG9wZXJhdGlvbiB0YWtlcyBPKGxvZyBuKQogICAgdm9pZCBhZGRSZWN0YW5nbGUoaW50IGlkLCBSZWN0YW5nbGUgcikgewogICAgICAgIHIuaWQgPSBpZDsKICAgICAgICB0cmVlRGF0YS5wdXNoX2JhY2socik7CiAgICAgICAgLy8gTm90ZTogSW4gYSByZWFsIFItVHJlZSwgdGhpcyB3b3VsZCBpbnZvbHZlIHJlYmFsYW5jaW5nIHRoZSB0cmVlIG5vZGVzLgogICAgfQoKICAgIC8vIFJlcXVpcmVtZW50OiBRdWVyeSBvcGVyYXRpb24gdGFrZXMgTyhsb2cgbikKICAgIHZlY3RvcjxpbnQ+IHF1ZXJ5UmVjdGFuZ2xlKFJlY3RhbmdsZSBxKSB7CiAgICAgICAgdmVjdG9yPGludD4gcmVzdWx0czsKICAgICAgICAvLyBJbiBhIHJlYWwgdHJlZSBsaWJyYXJ5LCB0aGlzIHRyYXZlcnNlcyBvbmx5IHJlbGV2YW50IGJyYW5jaGVzCiAgICAgICAgZm9yIChjb25zdCBhdXRvJiByZWN0IDogdHJlZURhdGEpIHsKICAgICAgICAgICAgaWYgKHJlY3QuaW50ZXJzZWN0cyhxKSkgewogICAgICAgICAgICAgICAgcmVzdWx0cy5wdXNoX2JhY2socmVjdC5pZCk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJlc3VsdHM7CiAgICB9Cn07CgovLyAtLS0gTUFQLVJFRFVDRSBMT0dJQyAoQ2FzZSAxOiBNYXAtT25seSBKb2luKSAtLS0KCi8qKgogKiBAYnJpZWYgUGVyZm9ybXMgYSBTcGF0aWFsIEpvaW4gdXNpbmcgdGhlIEJyb2FkY2FzdCBzdHJhdGVneS4KICogKiBDYXNlIDE6IFRhYmxlIEEgaXMgc21hbGwgZW5vdWdoIHRvIGZpdCBpbiBtZW1vcnkuCiAqIFdlIGJ1aWxkIHRoZSBzcGF0aWFsIGluZGV4IChUcmVlKSBvbmNlIGFuZCB0aGVuIHN0cmVhbSBUYWJsZSBCLgogKi8Kdm9pZCBicm9hZGNhc3RTcGF0aWFsSm9pbihjb25zdCB2ZWN0b3I8UmVjdGFuZ2xlPiYgc21hbGxUYWJsZUEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB2ZWN0b3I8UmVjdGFuZ2xlPiYgbGFyZ2VUYWJsZUJQYXJ0aXRpb24pIHsKICAgIAogICAgLy8gMS4gSU5JVElBTElaRSB0aGUgVHJlZQogICAgR2VvVHJlZSBzcGF0aWFsSW5kZXg7CgogICAgLy8gMi4gQlJPQURDQVNUIFBIQVNFOiBCdWlsZCB0aGUgdHJlZSBmcm9tIHRoZSBzbWFsbCB0YWJsZSAoZS5nLiwgQ2l0aWVzKQogICAgLy8gVGhpcyBoYXBwZW5zIG9uY2UgcGVyIE1hcHBlciB3b3JrZXIuCiAgICBmb3IgKGNvbnN0IGF1dG8mIGNpdHkgOiBzbWFsbFRhYmxlQSkgewogICAgICAgIHNwYXRpYWxJbmRleC5hZGRSZWN0YW5nbGUoY2l0eS5pZCwgY2l0eSk7CiAgICB9CgogICAgCgogICAgLy8gMy4gTUFQIFBIQVNFOiBTdHJlYW0gdGhlIGxhcmdlIHRhYmxlIChlLmcuLCBVYmVyIFRyaXBzKQogICAgLy8gV2UgY2hlY2sgZWFjaCB0cmlwIGFnYWluc3QgdGhlIGluZGV4ZWQgY2l0aWVzLgogICAgY291dCA8PCAiLS0tIFNwYXRpYWwgSm9pbiBSZXN1bHRzIC0tLSIgPDwgZW5kbDsKICAgIGNvdXQgPDwgIkNpdHlJRFx0VHJpcElEIiA8PCBlbmRsOwoKICAgIGZvciAoY29uc3QgYXV0byYgdHJpcCA6IGxhcmdlVGFibGVCUGFydGl0aW9uKSB7CiAgICAgICAgLy8gUXVlcnkgcmV0dXJucyBhbGwgQ2l0eSBJRHMgdGhhdCB0aGUgY3VycmVudCB0cmlwIGludGVyc2VjdHMKICAgICAgICB2ZWN0b3I8aW50PiBtYXRjaGluZ0NpdHlJZHMgPSBzcGF0aWFsSW5kZXgucXVlcnlSZWN0YW5nbGUodHJpcCk7CgogICAgICAgIGZvciAoaW50IGNpdHlJZCA6IG1hdGNoaW5nQ2l0eUlkcykgewogICAgICAgICAgICAvLyAiRW1pdCIgdGhlIGpvaW4gcmVzdWx0CiAgICAgICAgICAgIGNvdXQgPDwgY2l0eUlkIDw8ICJcdCIgPDwgdHJpcC5pZCA8PCBlbmRsOwogICAgICAgIH0KICAgIH0KfQoKLy8gLS0tIE1BSU4gRVhFQ1VUSU9OIC0tLQoKaW50IG1haW4oKSB7CiAgICAvLyBEYXRhc2V0IEE6IFNtYWxsIFRhYmxlIChlLmcuLCBDaXR5IEJvdW5kYXJpZXMpCiAgICAvLyBGb3JtYXQ6IHtJRCwgbWluWCwgbWluWSwgbWF4WCwgbWF4WX0KICAgIHZlY3RvcjxSZWN0YW5nbGU+IGNpdGllcyA9IHsKICAgICAgICB7MSwgMC4wLCAwLjAsIDUuMCwgNS4wfSwgICAvLyBDaXR5IEEKICAgICAgICB7MiwgMTAuMCwgMTAuMCwgMTUuMCwgMTUuMH0gLy8gQ2l0eSBCCiAgICB9OwoKICAgIC8vIERhdGFzZXQgQjogTGFyZ2UgVGFibGUgUGFydGl0aW9uIChlLmcuLCBVYmVyIFRyaXBzKQogICAgdmVjdG9yPFJlY3RhbmdsZT4gdHJpcHMgPSB7CiAgICAgICAgezEwMSwgMi4wLCAyLjAsIDMuMCwgMy4wfSwgICAvLyBJbnNpZGUgQ2l0eSBBCiAgICAgICAgezEwMiwgNC4wLCA0LjAsIDYuMCwgNi4wfSwgICAvLyBJbnRlcnNlY3RzIENpdHkgQQogICAgICAgIHsxMDMsIDEyLjAsIDEyLjAsIDE4LjAsIDE4LjB9LCAvLyBJbnRlcnNlY3RzIENpdHkgQgogICAgICAgIHsxMDQsIDIwLjAsIDIwLjAsIDI1LjAsIDI1LjB9ICAvLyBNYXRjaGVzIG5vdGhpbmcKICAgIH07CgogICAgLy8gUnVuIHRoZSBkaXN0cmlidXRlZCBqb2luIHNpbXVsYXRpb24KICAgIGJyb2FkY2FzdFNwYXRpYWxKb2luKGNpdGllcywgdHJpcHMpOwoKICAgIHJldHVybiAwOwp9