Home > Programming > Viết lại ví dụ tính pi.

Viết lại ví dụ tính pi.

Hầu hết các ví dụ mà Hadoop cung cấp sẵn đều viết theo cách cũ, tuy chúng vẫn chạy được trên phiên bản 0.20.2 nhưng đều được chú thích là deprecated. Rất có thể trong các version sau này, phong cách lập trình đó (bao gồm các hàm số, các lớp cũ …) sẽ bị bỏ hẳn. Vì vậy làm quen với phong cách mới là cần thiết. Bài này dựa trên cơ sở ví dụ dùng xác xuất tính giá trị số pi để viết lại bài toán.

Phân tích:

Trong hình sau, 1 đường tròn (bk 0.5) nội tiếp 1 hình vuông (cạnh 1), lấy một điểm bất kì (ngẫu nhiên) trong hình vuông, xác xuất để điểm này lọt trong hình tròn là:

K= Stròn/Svuông=pi*0.252/12=pi/4

Do đó chỉ cần lặp lại nhiều lần thí nghiệm này sẽ tính được số K (bằng số điểm lọt trong đường tròn chia tổng số lần thí nghiệm).

Code + Chú thích:

Mapper:

import java.io.IOException;
import java.util.Random;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.mapreduce.Mapper;

public class piMapper extends Mapper<LongWritable,Writable,LongWritable,LongWritable> {//Không dùng extends MapReduceBase inplements Mapper
static Random r = new Random();
long numInside;

public piMapper()
{
numInside = 0L;
}

public void map(LongWritable key, Writable values,Context context)

//Không dùng Collector & Reporter
throws IOException,InterruptedException {
long nSamples = key.get();// lấy số lần thí nghiệm của mỗi Map
for(long idx = 0L; idx < nSamples; idx++)
{
double x = r.nextDouble();
double y = r.nextDouble();

//(x,y) là một điểm trong hình vuông
double d = (x – 0.5D) * (x – 0.5D) + (y – 0.5D) * (y – 0.5D);//bình phương khoảng cách đến tâm
if(d <= 0.25D)//nếu bé hơn bình phương bán kính hình tròn
numInside++;//thì lọt vào trong hình tròn
if(idx%10000==1L)
context.setStatus(new String().concat(“Already done “).concat((new LongWritable(idx)).toString()).concat(” samples.”));

//nếu quá 600s (có thể chỉnh được bằng tham số mapred.tasktracker.expiry.interval) mà Map ko gởi report vế cho JobTracker thì Map đó xem như vô hiệu, nên ở đây thiết lập định kì gởi tin về.
}
context.write(new LongWritable(0L), new LongWritable(numInside));//mỗi Map đều xuất ra 1 cặp (0, numInside)
}

}

Reducer:

import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.mapreduce.Reducer;

public class piReducer extends Reducer<LongWritable,LongWritable,LongWritable,LongWritable> {
long numInside;

public piReducer()
{
numInside = 0L;
}
public void reduce(LongWritable key, Iterable<LongWritable> value,Context context)
throws IOException,InterruptedException {
for(LongWritable val:value)//tất cả các cặp do các Map xuất ra đều có cùng key (=0) nên được xâu lại thành 1 chuỗi, ở đây đọc từng giá trị của chuỗi rồi tính tổng của chúng
{
long num = val.get();
numInside += num;
}
context.write(new LongWritable(0L),new LongWritable(numInside));//lưu ý kết quả được viết vào file dạng part-r-nnnnn (ở đây chỉ có 1 file kq nên là part-r-00000, khác với cách cũ là dạng part-nnnnn)
}

}

Driver:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.SequenceFileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class pi {

public static void main(String[] args)throws Exception {
Configuration conf = new Configuration();
Job job=new Job(conf,”piEstimator”);//không dùng JobConf

job.setJarByClass(pi.class);
job.setOutputKeyClass(LongWritable.class);
job.setOutputValueClass(LongWritable.class);
job.setMapperClass(piMapper.class);
job.setReducerClass(piReducer.class);
job.setInputFormatClass(SequenceFileInputFormat.class);
job.setOutputFormatClass(SequenceFileOutputFormat.class);
if(args.length < 2)
{
System.err.println(“Usage: pi <nMaps> <nSamples>”);
} else
{
int nMaps = Integer.parseInt(args[0]);//có bao nhiêu Map
long nSamples = Long.parseLong(args[1]);//Mỗi Map tiến hành lấy bao nhiêu điểm
System.out.println((new StringBuilder()).append(“Number of Maps = “).append(nMaps).append(” Samples per Map = “).append(nSamples).toString());
Path tmpDir = new Path(“piEstimator”);
Path inDir = new Path(tmpDir, “in”);
Path outDir = new Path(tmpDir, “out”);
FileSystem fileSys=FileSystem.get(conf);
for(int idx = 0; idx < nMaps; idx++)
{
Path file = new Path(inDir, (new StringBuilder()).append(“part”).append(idx).toString());//tạo 1 file input cho mỗi Map
SequenceFile.Writer writer = SequenceFile.createWriter(fileSys, conf, file, LongWritable.class, LongWritable.class, SequenceFile.CompressionType.NONE);
writer.append(new LongWritable(nSamples), new LongWritable(0L));//viết giá trị vào file
writer.close();
System.out.println((new StringBuilder()).append(“Wrote input for Map #”).append(idx).toString());
}
FileInputFormat.addInputPath(job, inDir);
FileOutputFormat.setOutputPath(job, outDir);

long startTime = System.currentTimeMillis();
job.waitForCompletion(true);
System.out.println((new StringBuilder()).append(“Job Finished in “).append((double)(System.currentTimeMillis() – startTime) / 1000D).append(” seconds”).toString());
Path outFile = new Path(outDir, “part-r-00000”);//lấy đường dẫn của file kq
SequenceFile.Reader reader = new SequenceFile.Reader(fileSys, outFile, conf);
LongWritable numInside = new LongWritable();
LongWritable x = new LongWritable();
reader.next(x, numInside);// đọc kq
reader.close();
System.out.println((new StringBuilder()).append(“Estimated value of PI is “).append(((double)numInside.get() * 4D) / (double)((long)nMaps * nSamples)));
fileSys.delete(tmpDir, true);//xoá thư mục hoạt động của chương trình.
}
}

}

Nên lưu ý, các lớp Mapper, Reducer, SequenceFileInputFormat, SequenceFileOutputFormat…tuy có cùng tên với ví dụ cũ nhưng thực ra chúng ở trong các gói khác (xem phần inport để biết ở gói nào).

Trong Eclipse, muốn chạy ví dụ thì trước hết phải nhấp chuột phải chọn Run–>Run Configuration để thêm vào mục arguments 2 tham số (ví dụ 4 1000 nếu bạn muốn chạy 4 Map, mỗi Map lấy 1000 điểm), rối mới nhấp chuột phải chọn Run–>Run on Hadoop. Quá trình truyền dữ liệu qua lại của các Node tốn một thời gian nhất định, nên khi số điểm lấy quá ít thì chạy trên nhiều Map có thể lâu hơn chạy trên 1 Map (có số điểm =tổng các Map), vì trong trường hợp này, thời gian tính toán rất nhỏ so với thời gian truyền dữ liệu qua lại giữa các Node. Do đó nếu muốn thể hiên tính ưu việt của cloud computing thì nên chọn số lớn 1 chút. Kết thúc bài viết, mời bạn xem kết quả chạy thử sau:

số Map số điểm mỗi map Tổng cộng thời gian chạy(s) giá trị pi
1 4.000.000.000 4.000.000.000 1783,693 3,141579593
1 4.000.000.000 4.000.000.000 1811,731 3,14158139
4 1.000.000.000 4.000.000.000 600,449 3,141606980
4 1.000.000.000 4.000.000.000 356,812 3,141566272
4 1.000.000.000 4.000.000.000 345,009 3,141593037
1 4.000.000.000 4.000.000.000 684,115 3,141596735
1 4.000.000.000 4.000.000.000 1050,163 3,141589779
1 4.000.000.000 4.000.000.000 1573,775 3,141562377
4 1.000.000.000 4.000.000.000 665,757 3,14161285
4 1.000.000.000 4.000.000.000 336,199 3,141600342
1 4.000.000.000 4.000.000.000 1057,472 3,141611117
Categories: Programming Tags: ,
  1. mikado
    July 19, 2011 at 2:14 PM

    mình băn khoăn về phong cách lập trình mới và cũ tỏng Hadoop là gì?

  2. July 22, 2011 at 6:00 PM

    2 cái ko khác nhau nhiều, trong bản Hadoop mà bạn down về có nhiều ví dụ (file nén …examples.jar), bạn có thể dịch ngược từ file .class thành file .java để xem người ta viết thế nào.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: