PHP और Big Data: ऑक्सीमोरोन नहीं, बल्कि वास्तविकता
\n\nजब आप "बड़े डेटा का प्रसंस्करण" सुनते हैं, तो सबसे पहले दिमाग में Spark, Hadoop या Python के साथ Pandas आता है। PHP को इस सूची में आमतौर पर "लैंडिंग पेज और फ़ोरम की भाषा" के रूप में देखा जाता है। लेकिन आइए सच्चाई का सामना करें: यदि आपका प्रोजेक्ट पहले से PHP पर चल रहा है, तो केवल एक गीगाबाइट CSV को प्रोसेस करने के लिए उसे पूरी तरह से Go में फिर से लिखना, तोप से चिड़िया मारने जैसा है।
\n\nPHP Big Data को बखूबी संभाल सकता है, अगर समझदारी से काम लिया जाए। इस लेख में, हम वास्तविक तकनीकों पर चर्चा करेंगे: 10+ GB फ़ाइलों के साथ काम करते हुए सर्वर को कैसे न मारें, डेटाबेस से लाखों पंक्तियों को out of memory के बिना कैसे प्रोसेस करें, और PHP को एक वास्तविक डेटा पाइपलाइन में कैसे बदलें। कोई बकवास नहीं, केवल कोड और आर्किटेक्चरल समाधान।
PHP "बड़े डेटा" को क्यों "पसंद नहीं करता" (और इसे कैसे ठीक करें)
\n\nBig Data के संदर्भ में PHP की मुख्य समस्या इसका निष्पादन मॉडल है। स्क्रिप्ट क्रमिक रूप से निष्पादित होती है, सब कुछ मेमोरी में लोड करती है। 5 GB फ़ाइल पर file_get_contents() करने का प्रयास करें — सर्वर बस क्रैश हो जाएगा।
लेकिन एक अच्छी खबर भी है: PHP में स्ट्रीमिंग प्रोसेसिंग के लिए अंतर्निहित तंत्र हैं। बस file() या file_get_contents() जैसे "बर्बर" तरीकों को भूलकर जनरेटर, स्ट्रीम और chunk-क्वेरी पर स्विच करने की आवश्यकता है।
जनरेटर: आपका मुख्य उपकरण
\n\nजनरेटर (कीवर्ड yield) आपको पूरे सेट को मेमोरी में लोड किए बिना, एक-एक करके डेटा लौटाने की अनुमति देते हैं। यह बड़ी फ़ाइलों या DB से चयनों को पढ़ने के लिए आदर्श है।
उदाहरण: मेमोरी को मारे बिना 5 GB CSV फ़ाइल को पंक्ति दर पंक्ति पढ़ना:
\n\n<?php\nfunction readLargeCSV(string $filePath): Generator\n{\n $handle = fopen($filePath, 'r');\n if ($handle === false) {\n throw new RuntimeException("फ़ाइल खोलने में विफल: $filePath");\n }\n\n // BOM को छोड़ें, यदि है\n $bom = fread($handle, 3);\n if ($bom !== "\\xEF\\xBB\\xBF") {\n rewind($handle); // यदि BOM नहीं है, तो शुरुआत पर वापस जाएँ\n }\n\n while (($row = fgetcsv($handle, 0, ',')) !== false) {\n yield $row;\n }\n\n fclose($handle);\n}\n\n// उपयोग\nforeach (readLargeCSV('/data/orders_2024.csv') as $index => $row) {\n // प्रत्येक पंक्ति को एक-एक करके प्रोसेस करें\n if ($index === 0) {\n continue; // हेडर को छोड़ें\n }\n processOrder($row);\n}\n?>\n\nयह क्यों काम करता है? जनरेटर पूरी फ़ाइल को ऐरे में लोड नहीं करता। यह एक पंक्ति पढ़ता है — इसे देता है — अगली पढ़ता है। मेमोरी की खपत फ़ाइल के आकार की परवाह किए बिना कुछ किलोबाइट के स्तर पर रहती है।
\n\nबड़े डेटाबेस के साथ काम: Chunk-क्वेरी
\n\nयदि आपको MySQL से 5 मिलियन रिकॉर्ड प्रोसेस करने की आवश्यकता है, तो SELECT * FROM table करने का प्रयास न करें — यह DB और PHP दोनों को मार देगा। इसके बजाय, कर्सर या chunk-क्वेरी का उपयोग करें।
यहाँ PDO और chunk-पुनरावृत्ति के साथ सही दृष्टिकोण है:
\n\n<?php\nfunction processLargeTable(PDO $pdo, int $chunkSize = 1000, callable $callback): void\n{\n $offset = 0;\n $lastId = 0;\n\n // स्थिरता के लिए ORDER BY id का उपयोग करें\n $stmt = $pdo->prepare("SELECT * FROM orders WHERE id > :lastId ORDER BY id LIMIT :limit");\n\n do {\n $stmt->execute(['lastId' => $lastId, 'limit' => $chunkSize]);\n $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);\n\n if (empty($rows)) {\n break;\n }\n\n foreach ($rows as $row) {\n $callback($row);\n $lastId = $row['id']; // अंतिम प्रोसेस किए गए ID को याद रखें\n }\n\n // मेमोरी मुक्त करें\n unset($rows);\n $stmt->closeCursor();\n\n } while (true);\n}\n\n// उपयोग\n$pdo = new PDO('mysql:host=localhost;dbname=big_data', 'user', 'pass');\n$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);\n\np