infra: mirror light per-source Airflow DAGs + generators (GEN_ROWS), fix script path
This commit is contained in:
@@ -0,0 +1,65 @@
|
|||||||
|
"""Per-database light data generation DAGs.
|
||||||
|
|
||||||
|
Each DAG runs one generator script and accepts a `rows` value via the
|
||||||
|
dag_run conf (passed by the Command Center), exported as GEN_ROWS.
|
||||||
|
Triggerable independently so every database gets its own button.
|
||||||
|
"""
|
||||||
|
from airflow import DAG
|
||||||
|
from airflow.operators.python import PythonOperator
|
||||||
|
from datetime import datetime
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
SCRIPTS_DIR = "/opt/airflow/dags/scripts"
|
||||||
|
|
||||||
|
SOURCES = {
|
||||||
|
"postgres": "generate_postgres_sales_data.py",
|
||||||
|
"mysql": "generate_mysql_employee_data.py",
|
||||||
|
"mongodb": "generate_mongodb_events_data.py",
|
||||||
|
"cassandra": "generate_cassandra_telemetry_data.py",
|
||||||
|
"neo4j": "generate_neo4j_graph_data.py",
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFAULT_ROWS = {"neo4j": "2000"}
|
||||||
|
|
||||||
|
default_args = {"owner": "airflow", "retries": 0}
|
||||||
|
|
||||||
|
|
||||||
|
def make_runner(script: str, default_rows: str):
|
||||||
|
def _run(**context):
|
||||||
|
dag_run = context.get("dag_run")
|
||||||
|
conf = (dag_run.conf if dag_run else {}) or {}
|
||||||
|
rows = str(conf.get("rows") or default_rows)
|
||||||
|
env = dict(os.environ)
|
||||||
|
env["GEN_ROWS"] = rows
|
||||||
|
print(f"Running {script} with GEN_ROWS={rows}")
|
||||||
|
result = subprocess.run(
|
||||||
|
["python3", os.path.join(SCRIPTS_DIR, script)],
|
||||||
|
capture_output=True, text=True, env=env,
|
||||||
|
)
|
||||||
|
if result.stdout:
|
||||||
|
print(result.stdout[-4000:])
|
||||||
|
if result.stderr:
|
||||||
|
print("STDERR:", result.stderr[-4000:])
|
||||||
|
if result.returncode != 0:
|
||||||
|
raise Exception(f"{script} failed with return code {result.returncode}")
|
||||||
|
return _run
|
||||||
|
|
||||||
|
|
||||||
|
for _src, _script in SOURCES.items():
|
||||||
|
_dag_id = f"gen_{_src}"
|
||||||
|
_dag = DAG(
|
||||||
|
dag_id=_dag_id,
|
||||||
|
default_args=default_args,
|
||||||
|
description=f"Generate light data into {_src} (GEN_ROWS via conf.rows)",
|
||||||
|
schedule=None,
|
||||||
|
start_date=datetime(2025, 1, 1),
|
||||||
|
catchup=False,
|
||||||
|
tags=["data", "generation", _src],
|
||||||
|
)
|
||||||
|
PythonOperator(
|
||||||
|
task_id=f"generate_{_src}",
|
||||||
|
python_callable=make_runner(_script, DEFAULT_ROWS.get(_src, "5000")),
|
||||||
|
dag=_dag,
|
||||||
|
)
|
||||||
|
globals()[_dag_id] = _dag
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Script to generate fake telemetry data for Cassandra
|
||||||
|
Generates approximately 1GB of data
|
||||||
|
"""
|
||||||
|
|
||||||
|
from cassandra.cluster import Cluster
|
||||||
|
import random
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
import uuid
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Database connection details
|
||||||
|
DB_HOST = "10.0.21.51"
|
||||||
|
DB_PORT = "9042"
|
||||||
|
KEYSPACE = "telemetry"
|
||||||
|
TABLE_NAME = "device_metrics"
|
||||||
|
|
||||||
|
# Data generation settings
|
||||||
|
import os
|
||||||
|
TARGET_ROWS = int(os.getenv("GEN_ROWS", "5000")) # light, configurable via GEN_ROWS
|
||||||
|
BATCH_SIZE = min(5000, max(500, TARGET_ROWS))
|
||||||
|
|
||||||
|
# Sample data
|
||||||
|
METRIC_TYPES = ["temperature", "humidity", "pressure", "voltage", "current"]
|
||||||
|
DEVICE_PREFIX = "device-"
|
||||||
|
|
||||||
|
def generate_fake_device_metric():
|
||||||
|
"""Generate a single fake device metric"""
|
||||||
|
device_id = f"{DEVICE_PREFIX}{random.randint(1, 50000)}"
|
||||||
|
|
||||||
|
# Random timestamp within the last year
|
||||||
|
days_ago = random.randint(0, 365)
|
||||||
|
metric_ts = datetime.now() - timedelta(days=days_ago, hours=random.randint(0, 23),
|
||||||
|
minutes=random.randint(0, 59))
|
||||||
|
|
||||||
|
metric_type = random.choice(METRIC_TYPES)
|
||||||
|
metric_value = round(random.uniform(0.0, 100.0), 4)
|
||||||
|
|
||||||
|
# Generate a long payload field
|
||||||
|
payload = "X" * 200
|
||||||
|
|
||||||
|
return (device_id, metric_ts, metric_type, metric_value, payload)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print(f"Connecting to Cassandra at {DB_HOST}:{DB_PORT}...")
|
||||||
|
|
||||||
|
cluster = Cluster([DB_HOST], port=DB_PORT)
|
||||||
|
session = cluster.connect()
|
||||||
|
|
||||||
|
print(f"Generating {TARGET_ROWS} device metrics...")
|
||||||
|
print(f"Batch size: {BATCH_SIZE}")
|
||||||
|
|
||||||
|
total_generated = 0
|
||||||
|
batch = []
|
||||||
|
|
||||||
|
for i in range(TARGET_ROWS):
|
||||||
|
batch.append(generate_fake_device_metric())
|
||||||
|
|
||||||
|
if len(batch) >= BATCH_SIZE:
|
||||||
|
session.execute(
|
||||||
|
f"""
|
||||||
|
INSERT INTO {KEYSPACE}.{TABLE_NAME} (device_id, metric_ts, metric_type, metric_value, payload)
|
||||||
|
VALUES (%s, %s, %s, %s, %s)
|
||||||
|
""",
|
||||||
|
batch
|
||||||
|
)
|
||||||
|
total_generated += len(batch)
|
||||||
|
batch = []
|
||||||
|
|
||||||
|
if total_generated % 100000 == 0:
|
||||||
|
print(f"Generated {total_generated} rows...")
|
||||||
|
|
||||||
|
# Insert remaining rows
|
||||||
|
if batch:
|
||||||
|
session.execute(
|
||||||
|
f"""
|
||||||
|
INSERT INTO {KEYSPACE}.{TABLE_NAME} (device_id, metric_ts, metric_type, metric_value, payload)
|
||||||
|
VALUES (%s, %s, %s, %s, %s)
|
||||||
|
""",
|
||||||
|
batch
|
||||||
|
)
|
||||||
|
total_generated += len(batch)
|
||||||
|
|
||||||
|
session.shutdown()
|
||||||
|
cluster.shutdown()
|
||||||
|
|
||||||
|
print(f"Completed! Generated {total_generated} device metrics.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Script to generate fake event data for MongoDB
|
||||||
|
Generates approximately 1GB of data
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pymongo
|
||||||
|
import random
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
import uuid
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Database connection details
|
||||||
|
DB_HOST = "10.0.21.51"
|
||||||
|
DB_PORT = "27017"
|
||||||
|
DB_NAME = "supplychain"
|
||||||
|
COLLECTION_NAME = "events"
|
||||||
|
|
||||||
|
# Data generation settings
|
||||||
|
import os
|
||||||
|
TARGET_DOCUMENTS = int(os.getenv("GEN_ROWS", "5000")) # light, configurable via GEN_ROWS
|
||||||
|
BATCH_SIZE = min(5000, max(500, TARGET_DOCUMENTS))
|
||||||
|
|
||||||
|
# Sample data
|
||||||
|
EVENT_TYPES = ["INSERT", "UPDATE", "DELETE", "CREATE", "MODIFY"]
|
||||||
|
REGIONS = ["EU", "APAC", "LATAM", "NA", "EMEA"]
|
||||||
|
SOURCES = ["ERP", "WMS", "CRM", "SCM", "TMS"]
|
||||||
|
|
||||||
|
def generate_fake_event():
|
||||||
|
"""Generate a single fake event"""
|
||||||
|
event_id = uuid.uuid4()
|
||||||
|
event_type = random.choice(EVENT_TYPES)
|
||||||
|
region = random.choice(REGIONS)
|
||||||
|
source = random.choice(SOURCES)
|
||||||
|
|
||||||
|
# Random timestamp within the last year
|
||||||
|
days_ago = random.randint(0, 365)
|
||||||
|
ts = datetime.now() - timedelta(days=days_ago, hours=random.randint(0, 23),
|
||||||
|
minutes=random.randint(0, 59))
|
||||||
|
|
||||||
|
amount = random.uniform(100.0, 50000.0)
|
||||||
|
|
||||||
|
# Generate a long payload field (like the existing data)
|
||||||
|
payload = "X" * 500
|
||||||
|
|
||||||
|
return {
|
||||||
|
"event_id": event_id,
|
||||||
|
"type": event_type,
|
||||||
|
"region": region,
|
||||||
|
"source": source,
|
||||||
|
"amount": amount,
|
||||||
|
"ts": ts,
|
||||||
|
"payload": payload
|
||||||
|
}
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print(f"Connecting to MongoDB at {DB_HOST}:{DB_PORT}...")
|
||||||
|
|
||||||
|
client = pymongo.MongoClient(f"mongodb://{DB_HOST}:{DB_PORT}/")
|
||||||
|
db = client[DB_NAME]
|
||||||
|
collection = db[COLLECTION_NAME]
|
||||||
|
|
||||||
|
print(f"Generating {TARGET_DOCUMENTS} events...")
|
||||||
|
print(f"Batch size: {BATCH_SIZE}")
|
||||||
|
|
||||||
|
total_generated = 0
|
||||||
|
batch = []
|
||||||
|
|
||||||
|
for i in range(TARGET_DOCUMENTS):
|
||||||
|
batch.append(generate_fake_event())
|
||||||
|
|
||||||
|
if len(batch) >= BATCH_SIZE:
|
||||||
|
collection.insert_many(batch)
|
||||||
|
total_generated += len(batch)
|
||||||
|
batch = []
|
||||||
|
|
||||||
|
if total_generated % 100000 == 0:
|
||||||
|
print(f"Generated {total_generated} documents...")
|
||||||
|
|
||||||
|
# Insert remaining documents
|
||||||
|
if batch:
|
||||||
|
collection.insert_many(batch)
|
||||||
|
total_generated += len(batch)
|
||||||
|
|
||||||
|
client.close()
|
||||||
|
|
||||||
|
print(f"Completed! Generated {total_generated} events.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Script to generate fake employee event data for MySQL
|
||||||
|
Generates approximately 1GB of data
|
||||||
|
"""
|
||||||
|
|
||||||
|
import mysql.connector
|
||||||
|
import random
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
import uuid
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Database connection details
|
||||||
|
DB_HOST = "10.0.21.51"
|
||||||
|
DB_PORT = "3306"
|
||||||
|
DB_NAME = "hr"
|
||||||
|
DB_USER = "mo"
|
||||||
|
DB_PASSWORD = "Dell2026!"
|
||||||
|
|
||||||
|
# Data generation settings
|
||||||
|
import os
|
||||||
|
TARGET_ROWS = int(os.getenv("GEN_ROWS", "5000")) # light, configurable via GEN_ROWS
|
||||||
|
BATCH_SIZE = min(10000, max(500, TARGET_ROWS))
|
||||||
|
|
||||||
|
# Sample data
|
||||||
|
DEPARTMENTS = ["HR", "Operations", "Sales", "Marketing", "Finance", "IT", "Engineering", "Legal"]
|
||||||
|
ROLE_NAMES = ["Analyst", "Lead", "Manager", "Consultant", "Director", "Engineer", "Specialist", "Coordinator"]
|
||||||
|
REGIONS = ["EU", "APAC", "LATAM", "NA", "EMEA"]
|
||||||
|
EVENT_TYPES = ["TRANSFER", "PROMOTION", "TERMINATION", "HIRED", "SALARY_CHANGE", "DEPARTMENT_CHANGE"]
|
||||||
|
|
||||||
|
def generate_fake_employee_event():
|
||||||
|
"""Generate a single fake employee event"""
|
||||||
|
employee_id = random.randint(1, 100000)
|
||||||
|
department = random.choice(DEPARTMENTS)
|
||||||
|
role_name = random.choice(ROLE_NAMES)
|
||||||
|
region = random.choice(REGIONS)
|
||||||
|
event_type = random.choice(EVENT_TYPES)
|
||||||
|
|
||||||
|
# Random timestamp within the last 2 years
|
||||||
|
days_ago = random.randint(0, 730)
|
||||||
|
event_ts = datetime.now() - timedelta(days=days_ago, hours=random.randint(0, 23),
|
||||||
|
minutes=random.randint(0, 59))
|
||||||
|
|
||||||
|
salary_change = round(random.uniform(1000.0, 20000.0), 2) if random.random() > 0.3 else None
|
||||||
|
|
||||||
|
# Generate a long notes field (like the existing data)
|
||||||
|
notes = str(uuid.uuid4()) * 10
|
||||||
|
|
||||||
|
return (employee_id, department, role_name, region, event_type, salary_change, event_ts, notes)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print(f"Connecting to MySQL at {DB_HOST}:{DB_PORT}...")
|
||||||
|
|
||||||
|
conn = mysql.connector.connect(
|
||||||
|
host=DB_HOST,
|
||||||
|
port=DB_PORT,
|
||||||
|
database=DB_NAME,
|
||||||
|
user=DB_USER,
|
||||||
|
password=DB_PASSWORD
|
||||||
|
)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
print(f"Generating {TARGET_ROWS} employee events...")
|
||||||
|
print(f"Batch size: {BATCH_SIZE}")
|
||||||
|
|
||||||
|
total_generated = 0
|
||||||
|
batch = []
|
||||||
|
|
||||||
|
for i in range(TARGET_ROWS):
|
||||||
|
batch.append(generate_fake_employee_event())
|
||||||
|
|
||||||
|
if len(batch) >= BATCH_SIZE:
|
||||||
|
cursor.executemany(
|
||||||
|
"""
|
||||||
|
INSERT INTO employee_events (employee_id, department, role_name, region,
|
||||||
|
event_type, salary_change, event_ts, notes)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
|
""",
|
||||||
|
batch
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
total_generated += len(batch)
|
||||||
|
batch = []
|
||||||
|
|
||||||
|
if total_generated % 100000 == 0:
|
||||||
|
print(f"Generated {total_generated} rows...")
|
||||||
|
|
||||||
|
# Insert remaining rows
|
||||||
|
if batch:
|
||||||
|
cursor.executemany(
|
||||||
|
"""
|
||||||
|
INSERT INTO employee_events (employee_id, department, role_name, region,
|
||||||
|
event_type, salary_change, event_ts, notes)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
|
""",
|
||||||
|
batch
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
total_generated += len(batch)
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
print(f"Completed! Generated {total_generated} employee events.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,228 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Script to generate fake graph data for Neo4j
|
||||||
|
Generates approximately 1GB of data with nodes and relationships
|
||||||
|
"""
|
||||||
|
|
||||||
|
from neo4j import GraphDatabase
|
||||||
|
import random
|
||||||
|
import uuid
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Database connection details
|
||||||
|
DB_HOST = "10.0.21.51"
|
||||||
|
DB_PORT = "7687"
|
||||||
|
DB_USER = "neo4j"
|
||||||
|
DB_PASSWORD = "testpwd"
|
||||||
|
|
||||||
|
# Data generation settings
|
||||||
|
import os
|
||||||
|
TARGET_NODES = int(os.getenv("GEN_ROWS", "2000")) # light, configurable via GEN_ROWS
|
||||||
|
BATCH_SIZE = min(1000, max(200, TARGET_NODES))
|
||||||
|
|
||||||
|
# Sample data
|
||||||
|
PRODUCT_CATEGORIES = ["Electronics", "Clothing", "Food", "Furniture", "Toys", "Books"]
|
||||||
|
SUPPLIER_REGIONS = ["EU", "APAC", "LATAM", "NA", "EMEA"]
|
||||||
|
RELATIONSHIP_TYPES = ["SUPPLIES", "RELATED_TO", "COMPATIBLE_WITH", "PART_OF"]
|
||||||
|
|
||||||
|
def generate_fake_product():
|
||||||
|
"""Generate a single fake product node"""
|
||||||
|
product_id = str(uuid.uuid4())
|
||||||
|
name = f"Product-{random.randint(1000, 999999)}"
|
||||||
|
category = random.choice(PRODUCT_CATEGORIES)
|
||||||
|
price = round(random.uniform(10.0, 1000.0), 2)
|
||||||
|
stock = random.randint(0, 1000)
|
||||||
|
|
||||||
|
# Generate a long description field
|
||||||
|
description = "X" * 200
|
||||||
|
|
||||||
|
return {
|
||||||
|
"product_id": product_id,
|
||||||
|
"name": name,
|
||||||
|
"category": category,
|
||||||
|
"price": price,
|
||||||
|
"stock": stock,
|
||||||
|
"description": description
|
||||||
|
}
|
||||||
|
|
||||||
|
def generate_fake_supplier():
|
||||||
|
"""Generate a single fake supplier node"""
|
||||||
|
supplier_id = str(uuid.uuid4())
|
||||||
|
name = f"Supplier-{random.randint(1000, 999999)}"
|
||||||
|
region = random.choice(SUPPLIER_REGIONS)
|
||||||
|
rating = round(random.uniform(1.0, 5.0), 1)
|
||||||
|
|
||||||
|
# Generate a long address field
|
||||||
|
address = "X" * 150
|
||||||
|
|
||||||
|
return {
|
||||||
|
"supplier_id": supplier_id,
|
||||||
|
"name": name,
|
||||||
|
"region": region,
|
||||||
|
"rating": rating,
|
||||||
|
"address": address
|
||||||
|
}
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print(f"Connecting to Neo4j at {DB_HOST}:{DB_PORT}...")
|
||||||
|
|
||||||
|
driver = GraphDatabase.driver(f"bolt://{DB_HOST}:{DB_PORT}",
|
||||||
|
auth=(DB_USER, DB_PASSWORD))
|
||||||
|
|
||||||
|
with driver.session() as session:
|
||||||
|
print(f"Generating {TARGET_NODES} product nodes...")
|
||||||
|
print(f"Batch size: {BATCH_SIZE}")
|
||||||
|
|
||||||
|
total_products = 0
|
||||||
|
total_suppliers = 0
|
||||||
|
product_ids = []
|
||||||
|
|
||||||
|
# Generate product nodes
|
||||||
|
batch = []
|
||||||
|
for i in range(TARGET_NODES):
|
||||||
|
product = generate_fake_product()
|
||||||
|
batch.append(product)
|
||||||
|
product_ids.append(product["product_id"])
|
||||||
|
|
||||||
|
if len(batch) >= BATCH_SIZE:
|
||||||
|
session.run(
|
||||||
|
"""
|
||||||
|
UNWIND $batch as row
|
||||||
|
CREATE (p:Product {
|
||||||
|
product_id: row.product_id,
|
||||||
|
name: row.name,
|
||||||
|
category: row.category,
|
||||||
|
price: row.price,
|
||||||
|
stock: row.stock,
|
||||||
|
description: row.description
|
||||||
|
})
|
||||||
|
""",
|
||||||
|
batch=batch
|
||||||
|
)
|
||||||
|
total_products += len(batch)
|
||||||
|
batch = []
|
||||||
|
|
||||||
|
if total_products % 50000 == 0:
|
||||||
|
print(f"Generated {total_products} product nodes...")
|
||||||
|
|
||||||
|
# Insert remaining products
|
||||||
|
if batch:
|
||||||
|
session.run(
|
||||||
|
"""
|
||||||
|
UNWIND $batch as row
|
||||||
|
CREATE (p:Product {
|
||||||
|
product_id: row.product_id,
|
||||||
|
name: row.name,
|
||||||
|
category: row.category,
|
||||||
|
price: row.price,
|
||||||
|
stock: row.stock,
|
||||||
|
description: row.description
|
||||||
|
})
|
||||||
|
""",
|
||||||
|
batch=batch
|
||||||
|
)
|
||||||
|
total_products += len(batch)
|
||||||
|
|
||||||
|
print(f"Generated {total_products} product nodes.")
|
||||||
|
|
||||||
|
# Generate supplier nodes (fewer than products)
|
||||||
|
print(f"Generating supplier nodes...")
|
||||||
|
target_suppliers = max(20, TARGET_NODES // 10)
|
||||||
|
batch = []
|
||||||
|
supplier_ids = []
|
||||||
|
|
||||||
|
for i in range(target_suppliers):
|
||||||
|
supplier = generate_fake_supplier()
|
||||||
|
batch.append(supplier)
|
||||||
|
supplier_ids.append(supplier["supplier_id"])
|
||||||
|
|
||||||
|
if len(batch) >= BATCH_SIZE:
|
||||||
|
session.run(
|
||||||
|
"""
|
||||||
|
UNWIND $batch as row
|
||||||
|
CREATE (s:Supplier {
|
||||||
|
supplier_id: row.supplier_id,
|
||||||
|
name: row.name,
|
||||||
|
region: row.region,
|
||||||
|
rating: row.rating,
|
||||||
|
address: row.address
|
||||||
|
})
|
||||||
|
""",
|
||||||
|
batch=batch
|
||||||
|
)
|
||||||
|
total_suppliers += len(batch)
|
||||||
|
batch = []
|
||||||
|
|
||||||
|
if batch:
|
||||||
|
session.run(
|
||||||
|
"""
|
||||||
|
UNWIND $batch as row
|
||||||
|
CREATE (s:Supplier {
|
||||||
|
supplier_id: row.supplier_id,
|
||||||
|
name: row.name,
|
||||||
|
region: row.region,
|
||||||
|
rating: row.rating,
|
||||||
|
address: row.address
|
||||||
|
})
|
||||||
|
""",
|
||||||
|
batch=batch
|
||||||
|
)
|
||||||
|
total_suppliers += len(batch)
|
||||||
|
|
||||||
|
print(f"Generated {total_suppliers} supplier nodes.")
|
||||||
|
|
||||||
|
# Create relationships between products and suppliers
|
||||||
|
print(f"Creating relationships...")
|
||||||
|
batch = []
|
||||||
|
total_relationships = 0
|
||||||
|
|
||||||
|
for product_id in product_ids:
|
||||||
|
# Each product is supplied by 1-3 random suppliers
|
||||||
|
num_suppliers = random.randint(1, 3)
|
||||||
|
for _ in range(num_suppliers):
|
||||||
|
supplier_id = random.choice(supplier_ids)
|
||||||
|
rel_type = random.choice(RELATIONSHIP_TYPES)
|
||||||
|
|
||||||
|
batch.append({
|
||||||
|
"product_id": product_id,
|
||||||
|
"supplier_id": supplier_id,
|
||||||
|
"rel_type": rel_type
|
||||||
|
})
|
||||||
|
|
||||||
|
if len(batch) >= BATCH_SIZE:
|
||||||
|
session.run(
|
||||||
|
"""
|
||||||
|
UNWIND $batch as row
|
||||||
|
MATCH (p:Product {product_id: row.product_id})
|
||||||
|
MATCH (s:Supplier {supplier_id: row.supplier_id})
|
||||||
|
CALL apoc.create.relationship(p, row.rel_type, {}, s) YIELD rel
|
||||||
|
RETURN rel
|
||||||
|
""",
|
||||||
|
batch=batch
|
||||||
|
)
|
||||||
|
total_relationships += len(batch)
|
||||||
|
batch = []
|
||||||
|
|
||||||
|
if total_relationships % 50000 == 0:
|
||||||
|
print(f"Created {total_relationships} relationships...")
|
||||||
|
|
||||||
|
if batch:
|
||||||
|
session.run(
|
||||||
|
"""
|
||||||
|
UNWIND $batch as row
|
||||||
|
MATCH (p:Product {product_id: row.product_id})
|
||||||
|
MATCH (s:Supplier {supplier_id: row.supplier_id})
|
||||||
|
CALL apoc.create.relationship(p, row.rel_type, {}, s) YIELD rel
|
||||||
|
RETURN rel
|
||||||
|
""",
|
||||||
|
batch=batch
|
||||||
|
)
|
||||||
|
total_relationships += len(batch)
|
||||||
|
|
||||||
|
print(f"Created {total_relationships} relationships.")
|
||||||
|
|
||||||
|
driver.close()
|
||||||
|
print(f"Completed! Generated {total_products} products, {total_suppliers} suppliers, and {total_relationships} relationships.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Script to generate fake sales order data for PostgreSQL
|
||||||
|
Generates approximately 1GB of data
|
||||||
|
"""
|
||||||
|
|
||||||
|
import psycopg2
|
||||||
|
import random
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
import uuid
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Database connection details
|
||||||
|
DB_HOST = "10.0.21.51"
|
||||||
|
DB_PORT = "5432"
|
||||||
|
DB_NAME = "postgres"
|
||||||
|
DB_USER = "mo"
|
||||||
|
DB_PASSWORD = "Dell2026!"
|
||||||
|
|
||||||
|
# Data generation settings
|
||||||
|
TARGET_ROWS = int(os.getenv("GEN_ROWS", "5000")) # light, configurable via GEN_ROWS
|
||||||
|
BATCH_SIZE = min(10000, max(500, TARGET_ROWS))
|
||||||
|
|
||||||
|
# Sample data
|
||||||
|
REGIONS = ["EU", "APAC", "LATAM", "NA", "EMEA"]
|
||||||
|
SALES_CHANNELS = ["STORE", "ONLINE", "MOBILE", "B2B"]
|
||||||
|
CURRENCIES = ["EUR", "USD", "GBP", "JPY", "CNY"]
|
||||||
|
ORDER_STATUSES = ["SHIPPED", "PENDING", "CANCELLED", "RETURNED", "DELIVERED"]
|
||||||
|
|
||||||
|
def generate_fake_order():
|
||||||
|
"""Generate a single fake sales order"""
|
||||||
|
customer_id = random.randint(1, 100000)
|
||||||
|
product_id = random.randint(1, 5000)
|
||||||
|
region = random.choice(REGIONS)
|
||||||
|
sales_channel = random.choice(SALES_CHANNELS)
|
||||||
|
|
||||||
|
# Random timestamp within the last 2 years
|
||||||
|
days_ago = random.randint(0, 730)
|
||||||
|
order_ts = datetime.now() - timedelta(days=days_ago, hours=random.randint(0, 23),
|
||||||
|
minutes=random.randint(0, 59))
|
||||||
|
|
||||||
|
amount = round(random.uniform(10.0, 10000.0), 2)
|
||||||
|
currency = random.choice(CURRENCIES)
|
||||||
|
order_status = random.choice(ORDER_STATUSES)
|
||||||
|
|
||||||
|
# Generate a long notes field (like the existing data)
|
||||||
|
notes = str(uuid.uuid4()) * 10
|
||||||
|
|
||||||
|
return (customer_id, product_id, region, sales_channel, order_ts,
|
||||||
|
amount, currency, order_status, notes)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print(f"Connecting to PostgreSQL at {DB_HOST}:{DB_PORT}...")
|
||||||
|
|
||||||
|
conn = psycopg2.connect(
|
||||||
|
host=DB_HOST,
|
||||||
|
port=DB_PORT,
|
||||||
|
database=DB_NAME,
|
||||||
|
user=DB_USER,
|
||||||
|
password=DB_PASSWORD
|
||||||
|
)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
print(f"Generating {TARGET_ROWS} sales orders...")
|
||||||
|
print(f"Batch size: {BATCH_SIZE}")
|
||||||
|
|
||||||
|
total_generated = 0
|
||||||
|
batch = []
|
||||||
|
|
||||||
|
for i in range(TARGET_ROWS):
|
||||||
|
batch.append(generate_fake_order())
|
||||||
|
|
||||||
|
if len(batch) >= BATCH_SIZE:
|
||||||
|
cursor.executemany(
|
||||||
|
"""
|
||||||
|
INSERT INTO sales_orders (customer_id, product_id, region, sales_channel,
|
||||||
|
order_ts, amount, currency, order_status, notes)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
|
""",
|
||||||
|
batch
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
total_generated += len(batch)
|
||||||
|
batch = []
|
||||||
|
|
||||||
|
if total_generated % 100000 == 0:
|
||||||
|
print(f"Generated {total_generated} rows...")
|
||||||
|
|
||||||
|
# Insert remaining rows
|
||||||
|
if batch:
|
||||||
|
cursor.executemany(
|
||||||
|
"""
|
||||||
|
INSERT INTO sales_orders (customer_id, product_id, region, sales_channel,
|
||||||
|
order_ts, amount, currency, order_status, notes)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
|
""",
|
||||||
|
batch
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
total_generated += len(batch)
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
print(f"Completed! Generated {total_generated} sales orders.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user