Các kiểu dữ liệu và định dạng trong Hadoop

Một phần của tài liệu XỬ lý dữ LIỆU PHÂN tán với MAPREDUCE và xây DỰNG ỨNG DỤNG MINH họa (Trang 46 - 87)

3 Thiết kế thuật toán cho MapReduce

4.4Các kiểu dữ liệu và định dạng trong Hadoop

Các kiểu dữ liệu 4.4.1

Trong Hadoop mọi kiểu dữ liệu đều thực thi lớp trừu tƣợng Writable. Lớp này định nghĩa giao thức de/serialization (giải tuần tự/tuần tự hóa). Lớp WritableComparable định nghĩa thứ tự sắp xếp và tất cả các keys phải thuộc kiểu này. Ngoài ra còn có các kiểu dữ liệu cụ thể khác nhau nhƣ IntWritable, LongWritable, Text…

Để cài đặt kiểu dữ liệu phức tạp trong Hadoop ta có thể mã hóa chúng thành dạng Text, sau đó sử dụng biểu thức chính quy (regular expressions) để chuyển đổi và trích xuất dữ liệu. Ví dụ: để mã hóa tọa độ của một điểm (x, y) ta có thể lƣu trữ ở dạng text với tọa độ 2 điểm cách nhau bằng khoảng trắng và nằm trên một dòng, sau đó đọc từng dòng và tách từ ra để chuyển đổi thành tọa độ. Một cách khác đó là định nghĩa một lớp mới có cài đặt lớp trừu tƣợng WritableComparable, nhƣng trƣờng hợp này phải cài đặt thêm cái hàm readFields, write và compareTo của WritableComparable.

Các định dạng đầu vào (input formats) 4.4.2

46 Hadoop xử lý nhiều loại định dạng dữ liệu khác nhau, từ file text đến các bảng ghi trong cơ sở dữ liệu.

Input Splits và Records:

Input Split là một khối dữ liệu đƣợc xử lý bởi một map task. Mỗi hàm map xử lý một input split. Mỗi input split đƣợc chia thành các records và hàm map xử lý lần lƣợt từng record theo định dạng key-value.

public interface InputSplit extends Writable { long getLength() throws IOException;

String[] getLocations() throws IOException; }

Một InputSplit có chiều dài theo byte và một tập các nơi lƣu trữ - là các chuỗi chứa hostname.

Đối với một ngƣời lập trình MapReduce thì không cần phải làm việc trên InputSplit, mà sẽ tạo ra một InputFormat. Một InputFormat chịu trách nhiệm tạo ra các InputSplit và chia chúng thành các Record. Đây là giao diện của InputFormat:

public interface InputFormat<K, V> {

InputSplit[] getSplits(JobConf job, int numSplits) throws IOException; RecordReader<K, V> getRecordReader(InputSplit split,

JobConf job,

Reporter reporter) throws IOException; }

Các lớp cụ thể của InputFormat:

FileInputFormat là lớp cài đặt cơ sở của các cài đặt của InputFormat sử dụng file làm nguồn dữ liệu. Nó cung cấp 2 thứ: nơi chứa các file đầu vào của một Job và một cài đặt để sinh các InputSplit cho các files. Việc chia các split thành Record đƣợc thực hiện bởi các lớp con của nó.

47

Hình 18. Hệ thống phân cấp các lớp của InputFormat Các files nhỏ và CombineFileInputFormat

Hadoop làm việc với một lƣợng nhỏ các file lớn tốt hơn là làm việc với một lƣợng lớn các file nhỏ. Lý do là FileInputFormat sinh các split theo kiểu mỗi split là một file hoặc là một phần của file. Nếu file quá nhỏ (nhỏ hơn HDFS block) và có nhiều thì mỗi map task sẽ xử lý rất ít đầu vào dẫn đến có rất nhiều map task làm cho hệ thống bị chậm. Ví dụ: Có 1 GB dữ liệu đƣợc chia thành 64MB block (khoảng 16 file) và 10000 tập tin 100KB. Thì việc xử lý 10000 tập tin nhỏ có thể chậm hơn cả chục hay trăm lần so với xử lý 16 file lớn. CombineFileInputFormat đƣợc thiết kế để giảm thiểu điều này, CombineFileInputFormat gộp nhiều file nhỏ vào thành 1 split giúp cho các map task có nhiều dữ liệu hơn để xử lý.

TextInputFormat là InputFormat mặc định, mỗi record là một dòng của input. Key có kiểu LongWritable là một byte offset (số byte) trong file tính từ đầu dòng. Value là nội dung của dòng đó.

KeyValueTextInputFormat: tƣơng tự TextInputFormat, nhƣng key đƣợc thay thành dạng Line1, Line2. ..

NlineInputFormat: tƣơng tự TextInputFormat nhƣng value là giá trị của nhiều dòng.

48 Ngoài ra, Hadoop còn hỗ trợ các định dạng đầu vào nhị phân, đầu vào là dữ liệu trong cơ sở dữ liệu quan hệ.

Các định dạng đầu ra (output formats) 4.4.3

Hadoop có các định dạng đầu ra tƣơng tứng với định dạng đầu vào:

49

4.5 Ứng dụng đếm từ (Wordcount) viết trong Hadoop

Input: Tập văn bản

Outut: Danh sách các từ cùng số lần xuất hiện của chúng trong tập văn bản.

// WordCountMapper.java import java.io.IOException; import java.util.StringTokenizer; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; (adsbygoogle = window.adsbygoogle || []).push({});

public class WordCountMapper extends

Mapper<LongWritable, Text, Text, IntWritable> { private Text word = new Text();

protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {

String line = value.toString();

StringTokenizer tokenizer = new StringTokenizer(line); while (tokenizer.hasMoreTokens()) { word.set(tokenizer.nextToken()); context.write(word, 1); } } }

Lớp Mapper của chƣơng trình wordcount. Hàm map nhận đầu vào là một dòng và chuyển dòng đó thành các từ thông qua lớp StringTokenizer. Sau đó ứng với mỗi từ thì ghi ra cặp key-value có key là từ đó và value bằng 1.

// WordCountReducer.java

import java.io.IOException;

import org.apache.hadoop.mapreduce.Reducer;

import org.apache.hadoop.io.IntWritable;

import org.apache.hadoop.io.Text;

public class WordCountReducer extends

Reducer<Text, IntWritable, Text, IntWritable> {

protected void reduce(Text key, Iterable<IntWritable> values,

Context context) throws IOException, InterruptedException { int sum = 0;

for (IntWritable value : values) { sum += value.get();

50

context.write(key, new IntWritable(sum)); }

}

Lớp Reducer của chƣơng trình wordcount. Chỉ đơn giản là dùng một biến sum để đếm tổng các giá trị trung gian mà Mapper gửi lên tƣơng ứng với key, sau đó đƣa ra kết quả là key và sum.

// WordCountDriver.java import java.io.IOException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.input.TextInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;

public class WordCountDriver {

public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException { Configuration conf = new Configuration();

Job job = new Job(conf, "wordcount"); job.setOutputKeyClass(Text.class);

job.setOutputValueClass(IntWritable.class); job.setInputFormatClass(TextInputFormat.class); job.setOutputFormatClass(TextOutputFormat.class); FileInputFormat.setInputPaths(job, new Path(args[0])); FileOutputFormat.setOutputPath(job, new Path(args[1])); job.setMapperClass(WordCountMapper.class);

job.setReducerClass(WordCountReducer.class); System.out.println(job.waitForCompletion(true)); }

}

Lớp Driver chứa hàm main để chạy chƣơng trình wordcount, sử dụng hai lớp WordCountMapper và WordCountReducer ở trên.

51

4.6 Các chương trình xây dựng trên nền Hadoop (adsbygoogle = window.adsbygoogle || []).push({});

Hadoop rất tốt để xử lý dữ liệu lớn nhƣng nếu viết mọi công việc xử lý bằng Java thì thƣờng rất phức tạp và tốn thời gian. Các nhà phân tích không muốn (hoặc không thể) viết Java. Chính vì thế cần có các ngôn ngữ cấp cao để tiện cho việc xử lý.

Hbase

Phiên bản mã nguồn mở của Bigtable.

Cài đặt chức năng ghi thêm vào file hiện còn thiếu trong HDFS.

Hình 20. Cấu trúc của Hbase Hive and Pig

Hive: Ứng dụng kho dữ liệu cho Hadoop sử dụng ngôn ngữ truy vấn là HQL tƣơng tự nhƣ SQL, các bảng đƣợc lƣu trữ trong HDFS thành các flat files. Hive đƣợc phát triển bởi facebook và này đã thành một phần mềm mã nguồn mỡ.

Pig: Hệ thống xử lý dữ liệu lớn. Scripts đƣợc viết bằng Pig Latin. Đƣợc phát triển bởi Yahoo!, nay là một phần mềm mã nguồn mở. Các chƣơng trình MapReduce đƣợc viết trong Pig ngắn gọn hơn nhiều so với viết trên Java.

52

Hình 21. Hive và Pig

4.7 Hadoop và CSDL quan hệ

Bảng so sánh giữa RDBMS (Relational Database Management System) Hadoop (MapReduce):

RDBMS MapReduce

Kích thƣớc dữ liệu Gigabytes Petabytes

Truy cập Tƣơng tác và hàng loạt Hàng loạt

Updates Đọc và ghi nhiều lần Ghi 1 lần, đọc nhiều lần

Cấu trúc Tĩnh Động

Tính toàn vẹn Cao Thấp

53

Chƣơng 5: MÃ NGUỒN MỞ LUCENE, SOLR VÀ NUTCH

5 Mã nguồn mở Lucene, Solr và Nutch

5.1 Mã nguồn mở Lucene

Năm 1998, Doug Cutting – từng là nhân viên của Excite, Yahoo, và đang làm việc tại Apache Software Foundation và Cloudera- đã bắt đầu tiến hành xây dựng thƣ viện tìm kiếm thông tin mã nguồn mở Lucene với mục tiêu phát triển nó thành một thƣ viện tìm kiếm tài liệu hoàn chỉnh, cho phép các nhà phát triển ứng dụng dễ dàng tích hợp chức năng tìm kiếm vào hệ thống của mình.

Lucene là một thƣ viện tìm kiếm thông tin có khả năng xử lý và khả năng mở rộng ở mức cao, cho phép chúng ta có thể tích hợp vào các ứng dụng. Lucene là một dự án mã nguồn mở và nguyên thuỷ đƣợc phát triển bằng ngôn ngữ Java, ngày nay Lucene đƣợc phát triển bằng nhiều ngôn ngữ khác nhau nhƣ Delphi, Perl, C#, C++, Python, PHP…

Thành phần chức năng chính của Lucene bao gồm hai phần: Thành phần tạo chỉ mục và thành phần tìm kiếm. Đây là hai thành phần quan trọng cho một hệ thống tìm kiếm.

Hình 22. Các thành phần Lucene hỗ trợ cho hệ thống tìm kiếm

Dữ liệu tìm đƣợc Biên dịch tài liệu

Phần tích tài liệu Lập chỉ mục Tập chỉ mục Thực thi truyvấn Xây dựng truy vấn Kết quả trả về

Giao diện ngƣời dùng

Ngƣời sử dụng Dữ liệu thô

54 (adsbygoogle = window.adsbygoogle || []).push({});

Thành phần tạo chỉ mục: bao gồm các phần chức năng xử lý tạo chỉ mục, từ văn bản đầu vào để cho ra kết quả là một tập chỉ mục. Lucene chỉ hỗ trợ trên văn bản sau khi đƣợc tách nội dung ở dạng ký tự thuần, nó cho phép lập chỉ mục trên từng trƣờng thông tin của văn bản và cho phép thiết lập hệ số cho từng trƣờng thông tin để nâng cao vai trò lúc tìm kiếm.

o Directory: cho phép định nghĩa vùng nhớ, xác định nơi lƣu trữ trên bộ nhớ ngoài và bộ nhớ trên RAM trong quá trình tạo chỉ mục.

o Document và Field: định nghĩa tài liệu và các trƣờng thông tin của tài liệu sử dụng cho lập chỉ mục, nó cũng sử dụng cho việc lấy kết quả trả về cho thành phần tìm kiếm.

o Analyzer: thực hiện chức năng xử lý và tách văn bản để lấy nội dung, chuẩn hóa, loại bỏ mục từ không cần thiết,… để chuẩn bị cho việc lập chỉ mục.

o IndexWriter: là phần chính trong thành phần Tạo chỉ mục, nó thực hiện việc tạo mới hoặc mở chỉ mục, sau đó thực hiện thêm mới hoặc cập nhật nội dung của chỉ mục .

Thành phần tìm kiếm: bao gồm các phần chức năng cho xử lý tìm kiếm, từ yêu cầu của ngƣời dùng, thông qua biên dịch và so khớp để lấy về kết quả tốt nhất. Lucene hỗ trợ nhiều loại truy vấn thuận tiện cho ngƣời sử dụng, nó cho phép tìm theo trƣờng thông tin hay các thiết lập nâng cao nhƣ sắp xếp kết quả, giới hạn thời gian hoặc số lƣợng kết quả, phân trang…

o Term: Term là một đơn vị cơ bản của tìm kiếm, tƣơng tự nhƣ thành phần Field, Term cũng bao gồm tên và giá trị tƣơng ứng.

o Query: bao gồm nhiều loại truy vấn khác nhau, nó chứa nhiều phƣơng thức, nhƣng hầu hết đều quan tâm đến việc thiết lập chỉ số Boost, cho phép Lucene hiểu truy vấn con nào là quan trọng hơn.

o IndexSearcher: cho phép tìm kiếm trên tập chỉ mục do IndexWriter tạo ra, đây là thành phần chỉ thực hiện nhiệm vụ mở tập chỉ mục, không cho phép chỉnh sửa hay thay đổi. Có nhiều phƣơng thức tìm kiếm, một trong số đó là lớp thành phần thực thi Searcher, với cách đơn giản là cung cấp một Query truy vấn, số lƣợng các liên kết cần trả về, và kết quả trả về sẽ là tập các đối tƣợng TopDoc. o TopDoc: là một lớp đơn giản, dùng cho việc chứa các thứ hạng cao nhất của N

tài liệu có liên quan đến truy vấn. Với mỗi đối tƣợng trong danh sách này sẽ cho một docID dùng để liên kết đến tài liệu nhận về.

Lucene không phải là một ứng dụng hay một máy tìm kiếm hoàn chỉnh để ngƣời dùng có thể sử dụng ngay, đây chỉ là một thƣ viện, nó cung cấp các thành phần quan trọng nhất của một máy tìm kiếm đó là tạo chỉ mục và truy vấn. Chính vì chỉ cung cấp các thành phần quan trọng trong việc tạo chỉ mục nên ngƣời dùng rất linh hoạt trong việc ứng dụng vào sản phẩm của mình, cũng nhƣ có một số cải tiến cho phù hợp hơn.

55

5.2 Mã nguồn mở Solr

Solr là một máy chủ tìm kiếm độc lập với các hàm API giống REST (Representational State Transfer). Bạn đƣa các documents cho nó (để đánh chỉ mục) thông qua XML, JSON hoặc nhị phân bằng HTTP . Và truy vấn thông qua HTTP GET và nhận đƣợc các kết quả XML, JSON hoặc nhị phân. Solr sử dụng thƣ viện tìm kiếm Lucene và mở rộng nó.

Các tính năng chính của Solr:

Khả năng tìm kiếm văn bản toàn diện (Full-Text Search)

Đƣợc chỉnh sửa để tối ƣu khi lƣu lƣợng tìm kiếm trên server lớn.

Sử dụng các chuẩn mở để giao tiếp với các hệ thống khác. Thông qua XML, JSON và HTTP.

Có giao diện quản lý server trên web toàn diện và dễ sử dụng.

Khả năng mở rộng cao – dễ dàng nhân bản hiệu quả tới các Solr Search Servers khác để cùng xử lý.

Sự mềm dẻo và khả năng chỉnh sửa dễ dàng thông qua cấu hình bằng XML. Sử dụng kiến trúc Plugin mở rộng, giúp cho việc thêm các chức năng mới dễ dàng hơn.

5.3 Mã nguồn mở Nutch

Nutch là một cài đặt mã nguồn mở của một search engine đƣợc Doug Cutting – Ngƣời sáng lập của cả Lucene và Hadoop, và Mike Cafarella khởi đầu. Nó cung cấp tất cả công cụ cần thiết để xây dựng một search engine.

Các lý do để tự xây dựng một Search Engine:

1. Transparency (sự trong suốt). Nutch là mã nguồn mở, vì thế mọi ngƣời có thể thấy đƣợc cách các thuật toán xếp hạng hoạt động. Với những search engines thƣơng mại, sự chi tiết về thuật toán là bí mật vì thế không thể biết một kết quả tìm kiếm đƣợc xếp hạng nhƣ thế nào. Hơn thế nữa, một vài search engines cho phép việc xếp hàng dựa trên việc trả tiền. Nutch phù hợp cho việc giảng dạy và các tổ chức chính phủ, khi mà sự rõ ràng của việc xếp hạng là quan trọng hơn.

2. Understanding (Sự hiểu biết). Chúng ta không có mã nguồn của Google, vì thế Nutch có lẽ là thứ tốt nhất chúng ta có. Rất thú vị để thấy cách hoạt động của một search engine lớn. Nutch còn thu hút các nhà nghiên cứu muốn thử các thuật toán tìm kiếm mới vì nó rất dễ mở rộng.

3. Extensibility (Sự mở rộng). Không thích cách các search engine khác hiển thị kết quả? Tự viết search engine sử dụng Nutch! Nutch rất mềm dẻo, nó có thể đƣợc tùy chỉnh và tích hợp vào trong ứng dụng.

56

Các tính năng chính của Nutch:

Thu thập dữ liệu, phân tích và đánh chỉ mục song song và phân tán thông qua việc sử dụng MapReduce và hệ thống file phân tán (Hadoop). (adsbygoogle = window.adsbygoogle || []).push({});

Hỗ trợ đánh chỉ mục nhiều loại định dạng: plain text, HTML, XML, ZIP, OpenDocument (OpenOffice.org), Microsoft Office (Word, Excel, Powerpoint), PDF, JavaScript, RSS, RTF…

Sử dụng cơ sở dữ liệu đồ thị liên kết (Link-graph database) để sử dụng trong thuật toán PageRank.

Hình 23. Sơ đồ hoạt động của Nutch khi sử dụng như một Crawler

Đầu tiên, có tập URLs khởi tạo, thông qua Injector chuyển nó vào CrawlDB. CrawlDB thông qua Generator sẽ tạo ra một Segment (lúc này trong Segment sẽ có một thƣ mục crawl_generate chứa các URLs cần thu thập dữ liệu). Fetcher sẽ dùng các URLs trong Segment để thu thập dữ liệu từ các trang web và cập nhật lại Segment (lúc này, Segment sẽ có thêm các dữ liệu thu thập đƣợc). Parser sử dụng dữ liệu trong Segment để phân tích ra text, URLs, metadata… Sau đó CrawlDBTool sẽ cập nhật thêm các URLs mới từ các trang web thu thập đƣợc vào trong CrawlDB. Quá trình này sẽ đƣợc lặp đi lặp bao nhiêu lần tùy theo việc cấu hình độ sâu cần thu thập trên mỗi trang web.

57

Hình 24. Sơ đồ đầy đủ của Nutch khi sử dụng như một Search Engine

Trong hình trên, dữ liệu thu thập từng phần (Segments) đƣợc sử dụng để tạo ra LinkDB (cơ sở dữ liệu chứa các liên kết). Sau đó Indexer sử dụng Segments, LinkDB và CrawlDB để đánh chỉ mục (sử dụng Lucene) tạo ra Index. Segments chứa các dữ liệu đã thu thập đƣợc, LinkDB đƣợc sử dụng trong thuật toán PageRank lúc đánh chỉ mục và CrawlDB chứa các URLs đã thu thập đƣợc. Searcher tìm kiếm các kết quả trong Index để trả về cho giao diện ngƣời dùng (Web).

5.4 MapReduce trong Nutch:

Cấu trúc dữ liệu chính trong Nutch 5.4.1

CrawlDatum: Cấu trúc dữ liệu dùng trong CrawlDB dùng để lƣu trữ thông tin của một URL, gồm có trạng thái, thời gian, số lần thử lại để thu thập dữ liệu, điểm số, giá trị băm, metadata và thời gian cập nhật của URL,… Các thuộc tính trong lớp này gồm:

private byte status;

private long fetchTime;

private byte retries;

private int fetchInterval;

private float score = 1.0f;

private byte[] signature = null;

private long modifiedTime;

private org.apache.hadoop.io.MapWritable metaData;

SelectorEntry: Cấu trúc dữ liệu sử dụng trong Generator, gồm có URL, CrawlDatum và Segnum (để chứa tên của segment).

58

Content: Cấu trúc dữ liệu sử dụng để chứa dữ liệu thu thập đƣợc, gồm các trƣờng:

private final static int VERSION = -1;

private int version;

private String url;

private String base;

private byte[] content;

private String contentType;

private Metadata metadata;

private MimeUtil mimeTypes;

ParseText: Chứa text trích xuất đƣợc từ dữ liệu thu thập đƣợc (adsbygoogle = window.adsbygoogle || []).push({});

Một phần của tài liệu XỬ lý dữ LIỆU PHÂN tán với MAPREDUCE và xây DỰNG ỨNG DỤNG MINH họa (Trang 46 - 87)