Hadoop MapReduce Join & Counter พร้อมตัวอย่าง

⚡ สรุปอย่างชาญฉลาด

MapReduce join จะรวมชุดข้อมูลขนาดใหญ่สองชุดเข้าด้วยกันโดยใช้คีย์ร่วมกัน ไม่ว่าจะภายใน mapper หรือ reducer ในขณะที่ MapReduce counter จะรวบรวมสถิติเกี่ยวกับงานเพื่อให้สามารถวัดผลข้อมูลที่ไม่ถูกต้องได้ แทนที่จะคาดเดา

  • 🔘 ข้อมูลพื้นฐานเกี่ยวกับการเข้าร่วม: ชุดข้อมูลที่มีขนาดเล็กกว่าจะถูกกระจายไปยังโหนดข้อมูลทุกโหนดและใช้เป็นฝั่งค้นหา
  • ☑️ การเชื่อมต่อฝั่งแผนที่: จำเป็นต้องแบ่งข้อมูลแต่ละส่วนออกเป็นส่วนย่อยๆ อย่างเท่าๆ กัน และจัดเรียงตามคีย์การเชื่อมต่อก่อนที่ฟังก์ชัน map จะทำงาน
  • ✅ การเชื่อมต่อด้านลดขนาด: ไม่จำเป็นต้องแบ่งพาร์ติชัน เนื่องจากทุกทูเพิลที่มีคีย์การเชื่อมต่อเดียวกันจะไปอยู่ในตัวลดทอนเดียวกัน
  • 🧪 ตัวอย่างการทำงาน: ไฟล์ DeptName.txt และ DeptStrength.txt จะถูกคัดลอกไปยัง HDFS และรวมเข้าด้วยกันโดยใช้ Dept_ID ผ่านไฟล์ jar ที่บรรจุไว้
  • 🛠️ ประเภทตัวนับ: งานทุกชิ้นจะมีกลุ่มตัวนับในตัว 5 กลุ่ม และตัวนับที่ผู้ใช้กำหนดเองจะถูกประกาศเป็น Java enum.
  • ⚠️ ใช้โดยเคาน์เตอร์: การเพิ่มค่าตัวนับในแต่ละระเบียนที่ขาดหายหรือไม่ถูกต้อง จะเปลี่ยนปัญหาด้านคุณภาพข้อมูลให้เป็นตัวเลขในรายงานผลการปฏิบัติงาน

บทช่วยสอนการใช้งาน Hadoop MapReduce join และ counter พร้อมตัวอย่างการใช้งานจริง

Join ใน MapReduce คืออะไร?

การดำเนินการ Join ใน MapReduce ใช้สำหรับรวมชุดข้อมูลขนาดใหญ่สองชุดเข้าด้วยกัน อย่างไรก็ตาม กระบวนการนี้เกี่ยวข้องกับการเขียนโค้ดจำนวนมากเพื่อทำการรวมชุดข้อมูลจริง การรวมชุดข้อมูลสองชุดเริ่มต้นด้วยการเปรียบเทียบขนาดของแต่ละชุดข้อมูล หากชุดข้อมูลหนึ่งมีขนาดเล็กกว่าอีกชุดข้อมูลหนึ่ง ชุดข้อมูลที่เล็กกว่าจะถูกกระจายไปยังโหนดข้อมูลทุกโหนดในคลัสเตอร์

เมื่อเข้าร่วมแล้ว แผนที่ลด ในกรณีที่การประมวลผลแบบกระจายตัว ตัว Mapper หรือ Reducer จะใช้ชุดข้อมูลขนาดเล็กกว่าในการค้นหาเรคอร์ดที่ตรงกันจากชุดข้อมูลขนาดใหญ่ จากนั้นจึงรวมเรคอร์ดเหล่านั้นเข้าด้วยกันเพื่อสร้างเรคอร์ดผลลัพธ์

ประเภทของการเข้าร่วม

การเชื่อมต่อข้อมูลใน Hadoop แบ่งออกเป็นสองประเภท ขึ้นอยู่กับตำแหน่งที่ทำการเชื่อมต่อจริง

  1. เข้าร่วมฝั่งแผนที่ — เมื่อการเชื่อมต่อข้อมูลเกิดขึ้นโดยตัวแมปเปอร์ จะเรียกว่าการเชื่อมต่อฝั่งแมป (map-side join) ในรูปแบบนี้ การเชื่อมต่อจะเกิดขึ้นก่อนที่ข้อมูลจะถูกนำไปใช้ในฟังก์ชันแมปจริง ๆ จำเป็นอย่างยิ่งที่ข้อมูลนำเข้าของแต่ละแมปจะต้องอยู่ในรูปแบบของพาร์ติชันและเรียงลำดับแล้ว นอกจากนี้ จำนวนพาร์ติชันต้องเท่ากันและต้องเรียงลำดับตามคีย์การเชื่อมต่อด้วย
  2. ข้อต่อด้านลด — เมื่อตัวลด (reducer) ทำการเชื่อมข้อมูล จะเรียกว่าการเชื่อมข้อมูลฝั่งลด (reduce-side join) การเชื่อมข้อมูลแบบนี้ไม่จำเป็นต้องมีชุดข้อมูลในรูปแบบที่มีโครงสร้าง (หรือแบ่งพาร์ติชัน) การประมวลผลฝั่งแมป (map side processing) จะสร้างคีย์การเชื่อมและทูเปิลที่เกี่ยวข้องของทั้งสองตาราง ผลจากการประมวลผลนี้ ทูเปิลทั้งหมดที่มีคีย์การเชื่อมเดียวกันจะตกไปอยู่ในตัวลดเดียวกัน ซึ่งจะทำการเชื่อมข้อมูลที่มีคีย์การเชื่อมเดียวกันนั้น

ผังกระบวนการโดยรวมของการรวมใน Hadoop แสดงอยู่ในไดอะแกรมด้านล่าง

แผนภาพแสดงขั้นตอนการทำงานเปรียบเทียบการเชื่อมต่อฝั่งแผนที่ (map-side join) กับการเชื่อมต่อฝั่งลดขนาด (reduce-side join) ใน Hadoop
ประเภทของการรวมใน Hadoop MapReduce

เมื่อเข้าใจสองรูปแบบนี้แล้ว ส่วนถัดไปจะอธิบายวิธีการใช้ reduce-side join กับไฟล์ข้อมูลขนาดเล็กสองไฟล์ของแผนก

วิธีรวมชุดข้อมูลสองชุด: ตัวอย่าง MapReduce

มีข้อมูลสองชุดอยู่ในไฟล์สองไฟล์ที่แตกต่างกัน (แสดงด้านล่าง) คีย์ Dept_ID มีอยู่ในทั้งสองไฟล์ เป้าหมายคือการใช้ MapReduce Join เพื่อรวมไฟล์เหล่านี้เข้าด้วยกัน

ไฟล์ข้อมูลนำเข้าแรกประกอบด้วยรหัสแผนกควบคู่กับชื่อแผนก

ไฟล์ 1
ไฟล์ข้อมูลเข้าชุดที่สองแสดงรายการรหัสแผนกควบคู่กับค่ากำลังคนของแผนก

ไฟล์ 2

Input: ชุดข้อมูลป้อนเข้าคือไฟล์ข้อความชื่อ DeptName.txt และ DeptStrength.txt

ดาวน์โหลดไฟล์อินพุตได้จากที่นี่

รับรองว่ามี Hadoop ติดตั้งเรียบร้อยแล้ว ก่อนเริ่มต้นกระบวนการจริงตามตัวอย่าง MapReduce Join ให้เปลี่ยนผู้ใช้เป็น 'hduser' (รหัสผู้ใช้ที่ใช้ในการกำหนดค่า Hadoop คุณสามารถเปลี่ยนไปใช้รหัสผู้ใช้ที่ใช้ในการกำหนดค่า Hadoop ได้)

su - hduser_

ข้อความแจ้งเตือนจะเปลี่ยนเป็นบัญชี Hadoop ดังแสดงด้านล่าง

เทอร์มินัลหลังจากเปลี่ยนไปใช้บัญชี hduser ด้วยคำสั่ง su

ขั้นตอน 1) คัดลอกไฟล์ zip ไปยังตำแหน่งที่คุณต้องการ

ไฟล์เก็บถาวร MapReduceJoin ที่ดาวน์โหลดมาจะถูกจัดเก็บไว้ในไดเร็กทอรีการทำงานที่เลือกไว้

ขั้นตอน 2) คลายการบีบอัดไฟล์ซิป

sudo tar -xvf MapReduceJoin.tar.gz

อดีตtracชื่อไฟล์ ted จะเลื่อนผ่านไปขณะที่ tar กำลังแตกไฟล์เก็บถาวร

รายการไฟล์ในคอนโซล เช่นtracted จาก MapReduceJoin.tar.gz

ขั้นตอน 3) ไปที่ไดเร็กทอรี MapReduceJoin/

cd MapReduceJoin/

พร้อมท์เชลล์หลังจากเปลี่ยนเข้าไปในไดเร็กทอรี MapReduceJoin แล้ว

ขั้นตอน 4) เริ่ม Hadoop

$HADOOP_HOME/sbin/start-dfs.sh
$HADOOP_HOME/sbin/start-yarn.sh

สคริปต์ทั้งสองจะแสดงรายชื่อของดีมอนที่พวกมันเรียกใช้งาน

ข้อความเริ่มต้นจากสคริปต์ดีมอน HDFS และ YARN

ขั้นตอน 5) DeptStrength.txt และ DeptName.txt เป็นไฟล์อินพุตที่ใช้สำหรับโปรแกรมตัวอย่าง MapReduce Join นี้

จำเป็นต้องคัดลอกไฟล์เหล่านี้ไปยัง เอชดีเอฟเอส โดยใช้คำสั่งด้านล่างนี้

$HADOOP_HOME/bin/hdfs dfs -copyFromLocal DeptStrength.txt DeptName.txt /

ไฟล์ข้อความอินพุตทั้งสองไฟล์ถูกคัดลอกไปยังไดเร็กทอรีรากของ HDFS แล้ว

ขั้นตอน 6) รันโปรแกรมโดยใช้คำสั่งด้านล่าง-

$HADOOP_HOME/bin/hadoop jar MapReduceJoin.jar MapReduceJoin/JoinDriver/DeptStrength.txt /DeptName.txt /output_mapreducejoin

คำสั่งจะถูกแสดงออกมาก่อน จากนั้นกระบวนการจะรายงานความคืบหน้าบนคอนโซล

การเรียกใช้ไฟล์ jar ของ MapReduceJoin ที่บรรจุอยู่ในบรรทัดคำสั่ง

เอาต์พุตคอนโซล tracราชาแห่งความคืบหน้าของงานร่วม MapReduce

ขั้นตอน 7) หลังจากดำเนินการเสร็จสิ้น ไฟล์ผลลัพธ์ (ชื่อ 'part-00000') จะถูกจัดเก็บไว้ในไดเร็กทอรี /output_mapreducejoin บน HDFS

สามารถดูผลลัพธ์ได้โดยใช้อินเทอร์เฟซบรรทัดคำสั่ง

$HADOOP_HOME/bin/hdfs dfs -cat /output_mapreducejoin/part-00000

บันทึกข้อมูลแผนกที่รวมกันพิมพ์จาก HDFS โดยใช้คำสั่ง cat

สามารถดูผลลัพธ์ได้ผ่านทางเว็บอินเตอร์เฟสเช่นกัน

หน้าเว็บอินเทอร์เฟซของ Hadoop ใช้สำหรับเข้าถึงเบราว์เซอร์ระบบไฟล์

จากนั้นเลือก 'เรียกดูระบบไฟล์' และไปยังไดเร็กทอรี /output_mapreducejoin

เรียกดูมุมมองระบบไฟล์ HDFS ไปยังไดเร็กทอรี output_mapreducejoin

เปิด part-r-00000

การเลือกไฟล์เอาต์พุต part-r-00000 ภายในมุมมองเบราว์เซอร์

ผลลัพธ์จะปรากฏขึ้น

ชื่อแผนกที่เข้าร่วมและจำนวนบุคลากรในแผนกจะแสดงในเบราว์เซอร์

หมายเหตุ: โปรดทราบว่าก่อนที่จะรันโปรแกรมนี้ในครั้งต่อไป คุณจะต้องลบไดเร็กทอรีเอาต์พุต /output_mapreducejoin

$HADOOP_HOME/bin/hdfs dfs -rm -r /output_mapreducejoin

ทางเลือกอื่นคือใช้ชื่ออื่นสำหรับไดเร็กทอรีเอาต์พุต

การเชื่อมต่อข้อมูลจะบอกคุณว่าข้อมูลมีลักษณะอย่างไร ส่วนตัวนับ ซึ่งจะกล่าวถึงในหัวข้อถัดไป จะบอกคุณว่ากระบวนการที่สร้างข้อมูลนั้นทำงานอย่างไร

ตัวนับใน MapReduce คืออะไร

ตัวนับใน MapReduce คือกลไกที่ใช้ในการรวบรวมและวัดข้อมูลทางสถิติเกี่ยวกับงานและเหตุการณ์ของ MapReduce ตัวนับจะเก็บข้อมูลต่างๆ ไว้ track คือค่าสถิติต่างๆ ของงานใน MapReduce เช่น จำนวนการดำเนินการที่เกิดขึ้นและความคืบหน้าของการดำเนินการ ตัวนับเหล่านี้ใช้สำหรับการวินิจฉัยปัญหาใน MapReduce

ตัวนับ Hadoop คล้ายกับการใส่ข้อความบันทึกลงในโค้ดสำหรับแผนที่หรือลดขนาด ข้อมูลนี้อาจเป็นประโยชน์สำหรับการวินิจฉัยปัญหาในการประมวลผลงาน MapReduce

โดยทั่วไป ตัวนับเหล่านี้ใน Hadoop จะถูกกำหนดไว้ในโปรแกรม (map หรือ reduce) และจะเพิ่มขึ้นระหว่างการทำงานเมื่อเกิดเหตุการณ์หรือเงื่อนไขเฉพาะ (ที่เฉพาะเจาะจงกับตัวนับนั้น) ตัวอย่างการใช้งานตัวนับ Hadoop ที่ดีมากอย่างหนึ่งคือ... track รายการที่ถูกต้องและไม่ถูกต้องจากชุดข้อมูลอินพุต

ประเภทของตัวนับ MapReduce

โดยพื้นฐานแล้ว MapReduce Counter มีอยู่ 2 ประเภท

  1. ตัวนับในตัวของ Hadoop: มีตัวนับ Hadoop ในตัวบางตัวที่มีอยู่สำหรับแต่ละงาน ด้านล่างนี้เป็นกลุ่มตัวนับในตัว -
    • ตัวนับงาน MapReduce — รวบรวมข้อมูลเฉพาะของงาน (เช่น จำนวนระเบียนข้อมูลขาเข้า) ในระหว่างการประมวลผล
    • ตัวนับระบบไฟล์ — รวบรวมข้อมูล เช่น จำนวนไบต์ที่อ่านหรือเขียนโดยงานนั้นๆ
    • ตัวนับรูปแบบไฟล์อินพุต — รวบรวมข้อมูลจำนวนไบต์ที่อ่านผ่าน FileInputFormat
    • ตัวนับ FileOutputFormat — รวบรวมข้อมูลจำนวนไบต์ที่เขียนผ่านฟังก์ชัน FileOutputFormat
    • เคาน์เตอร์งาน — ตัวนับเหล่านี้จะบันทึกสถิติโดยรวมของงาน เช่น จำนวนภารกิจที่เริ่มต้นสำหรับงานนั้นๆ
  2. ตัวนับที่ผู้ใช้กำหนดเอง: นอกเหนือจากตัวนับในตัวแล้ว ผู้ใช้ยังสามารถกำหนดตัวนับของตนเองได้โดยใช้ฟังก์ชันการทำงานที่คล้ายคลึงกันซึ่งมีอยู่ในภาษาโปรแกรม ตัวอย่างเช่น ใน Javaโดยใช้ 'enum' ในการกำหนดค่าตัวนับที่ผู้ใช้กำหนดเอง

💡 หมายเหตุเกี่ยวกับเวอร์ชัน: ตัวนับงานได้รับการดูแลโดยฝ่ายงานTracker ภายใต้ MRv1 บน YARN บทบาทนั้นเป็นของ MapReduce ApplicationMaster ดังนั้นชื่อตัวนับจึงยังคงอยู่ แต่ส่วนประกอบที่รายงานค่าเหล่านั้นได้เปลี่ยนไปแล้ว

งานหนึ่งๆ ไม่สามารถประกาศตัวนับได้ไม่จำกัดจำนวน mapreduce.job.counters.max โดยค่าเริ่มต้น การตั้งค่าจะจำกัดจำนวนรวมต่องานไว้ที่ 120 และงานที่ประกาศจำนวนมากกว่านั้นจะล้มเหลวพร้อมข้อความแสดงข้อผิดพลาด LimitExceededExceptionดังนั้น ตัวนับจึงมีไว้สำหรับสัญญาณโดยรวมเพียงไม่กี่อย่าง มากกว่าการนับจำนวนตามแต่ละคีย์

ตัวอย่างเคาน์เตอร์

ตัวอย่าง MapClass ที่มีตัวนับเพื่อนับจำนวนค่าที่หายไปและค่าที่ไม่ถูกต้อง ไฟล์ข้อมูลที่ใช้ในบทช่วยสอนนี้คือไฟล์ CSV ชื่อ SalesJan2009.csv

public static class MapClass
            extends MapReduceBase
            implements Mapper<LongWritable, Text, Text, Text>
{
    static enum SalesCounters { MISSING, INVALID };
    public void map ( LongWritable key, Text value,
                 OutputCollector<Text, Text> output,
                 Reporter reporter) throws IOException
    {
        
        //Input string is split using ',' and stored in 'fields' array
        String fields[] = value.toString().split(",", -20);
        //Value at 4th index is country. It is stored in 'country' variable
        String country = fields[4];
        
        //Value at 8th index is sales data. It is stored in 'sales' variable
        String sales = fields[8];
      
        if (country.length() == 0) {
            reporter.incrCounter(SalesCounters.MISSING, 1);
        } else if (sales.startsWith("\"")) {
            reporter.incrCounter(SalesCounters.INVALID, 1);
        } else {
            output.collect(new Text(country), new Text(sales + ",1"));
        }
    }
}

โค้ดตัวอย่างด้านบนแสดงการใช้งานตัวนับใน Hadoop MapReduce

ที่นี่ เคาน์เตอร์ขาย เป็นตัวนับที่กำหนดโดยใช้ 'อีนุมใช้สำหรับนับจำนวนข้อมูลที่ขาดหายไปและข้อมูลที่ไม่ถูกต้อง

ในโค้ดตัวอย่าง ถ้า 'ประเทศ'หากฟิลด์มีความยาวเป็นศูนย์ ค่าของฟิลด์นั้นจะหายไป และตัวนับที่เกี่ยวข้อง SalesCounters.MISSING จะถูกเพิ่มขึ้น'

ต่อไป ถ้า 'ขายหากฟิลด์เริ่มต้นด้วยเครื่องหมาย “ แสดงว่าเรคอร์ดนั้นไม่ถูกต้อง ซึ่งจะแสดงโดยการเพิ่มค่าตัวนับ SalesCounters.INVALID ขึ้นไปเรื่อยๆ

💡 หมายเหตุเกี่ยวกับ API: โค้ดด้านบนใช้ต้นฉบับ org.apache.hadoop.mapred API ที่ MapReduceBaseที่ Mapper อินเตอร์เฟซ, OutputCollector และ Reporter ปรากฏแยกกัน โค้ดปัจจุบันเขียนขึ้นโดยคำนึงถึงสิ่งต่อไปนี้ org.apache.hadoop.mapreduceโดยที่เพียงอันเดียว Context แทนที่ตัวเก็บรวบรวมและตัวรายงาน และตัวนับจะเพิ่มขึ้นทีละหนึ่ง context.getCounter(SalesCounters.MISSING).increment(1)แนวคิดเรื่องตัวนับนั้นเหมือนกันในทั้งสองแบบ

คำถามที่พบบ่อย

เลือกใช้รูปแบบ mapper เมื่อด้านใดด้านหนึ่งมีขนาดเล็กพอที่จะเก็บไว้ในหน่วยความจำบนทุกโหนดได้ เพราะจะข้ามขั้นตอนการสับเปลี่ยนข้อมูลไปโดยสิ้นเชิง เลือกใช้รูปแบบ reducer เมื่อทั้งสองด้านมีขนาดใหญ่หรือไม่เรียงลำดับ และยอมรับค่าใช้จ่ายเครือข่ายที่เพิ่มขึ้น

โมเดลเรียนรู้จากประวัติการทำงานในอดีตเพื่อทำนายเวลาในการทำงาน แนะนำขนาดการแบ่งงานและจำนวนตัวลดขนาด และตรวจจับความผิดปกติจากค่าตัวนับ นอกจากนี้ยังแจ้งเตือนงานที่มีค่าตัวนับบันทึกที่รั่วไหลหรืองานที่ล้มเหลวเกินช่วงปกติสำหรับไปป์ไลน์นั้นด้วย

Copilot สร้างโครงร่าง mapper และ reducer ที่ดูสมเหตุสมผล แต่กลับนำแพ็กเกจ mapred รุ่นเก่ามาผสมผสานกับแพ็กเกจ mapreduce รุ่นใหม่ในคลาสเดียวกัน ซึ่งจะทำให้คอมไพล์ไม่ผ่าน ควรแก้ไขการนำเข้าและลายเซ็นของเมธอดก่อนที่จะเชื่อถือตรรกะการทำงาน

นี่คือกลไกที่ส่งไฟล์ขนาดเล็กกว่าไปยังทุกโหนดก่อนที่งานจะเริ่มต้น จากนั้นแต่ละแมปเปอร์จะโหลดสำเนาไฟล์นั้นลงในแฮชแมปและค้นหาการจับคู่ในเครื่อง ซึ่งเป็นสิ่งที่ทำให้การเชื่อมต่อฝั่งแมปเปอร์เป็นไปได้

ข้อมูลเหล่านี้จะปรากฏในสรุปคอนโซลเมื่องานเสร็จสมบูรณ์ แสดงในประวัติงานและหน้าเว็บตัวจัดการทรัพยากร และสามารถอ่านได้ทางโปรแกรมจากอ็อบเจ็กต์งาน เพื่อให้ไดรเวอร์สามารถตรวจสอบและยกเลิกการทำงานที่ผิดพลาดได้

อ็อบเจ็กต์ Context เพียงตัวเดียว ทำหน้าที่ประมวลผลงานที่ OutputCollector และ Reporter เคยแบ่งกันทำ ดังนั้นเอาต์พุตจะถูกเขียนและตัวนับจะเพิ่มขึ้นผ่านแฮนเดิลเดียวกันที่ส่งไปยังเมธอด map

สำหรับงานรายงานข่าวส่วนใหญ่ คำตอบคือไม่ เข้าร่วม HiveQL เมื่อแปลงเป็นรูปแบบการสลับและผสานแบบเดียวกันแล้ว จะเหลือเพียงไม่กี่บรรทัด การเขียนโค้ดด้วยมือเองนั้นคุ้มค่าเมื่อตรรกะการผสานไม่ตรงกับข้อความในคำสั่ง SQL

Hadoop ไม่อนุญาตให้เขียนข้อมูลลงในไดเร็กทอรีเอาต์พุตที่มีอยู่แล้ว เพื่อป้องกันไม่ให้ผลลัพธ์ที่เสร็จสมบูรณ์ถูกเขียนทับ ดังนั้น ให้ลบไดเร็กทอรีนั้นแบบเรียกซ้ำก่อน หรือระบุพาธเอาต์พุตอื่นในการรันครั้งถัดไป

สรุปโพสต์นี้ด้วย: