扩展sawzall代码实现自定义接口

| 2014年5月4日

使用sawzall开发mr程序虽然很快,不过也有不少限制,尤其对于新手来说,比如不能直接像c++一样调用线程的库,不过它提供了一种扩展开发的方式,我们可以自己修改sawzall代码实现新的功能接口,在下载平台的sawzall代码中,我们就扩展了一种聚合器,两个和我们web相关的功能接口:连接我们的domain service进行聚合域名的识别,根据url进行域名提取。这里以使用我们comm库中的url类进行域名提取为例来说明一下sawzall的功能函数扩展。

首先来看一下sawzall代码的目录结构和其用途说明

Szl的src目录下有如下一些文件夹: app:包含szl本地化工具的相关实现,

app/tests/目录下还包含了一个MapReduce的实现实例

contrib:内含Emacs的一个插件

emitters:一系列聚合器实现

emitvalues:sawzall相关一些基本类型定义,包括decoder,emitter,encoder,tableentry等

engine:sawzall语言相关,包括词法分析,语法分析,执行引擎

fmt:格式化输出相关

intrinsics:一些常见的运算支持,也是功能扩展接口,比如压缩,排序,数据额函数等

protoc_plugin:protobuf相关工具

public:公开的头文件

utilities:基本工具类

 

我在实现的扩展功能就是从参考intrinsics目录下的其它方法来实现的,例如我添加了一个新文件:urldomainintrinsics.cc ,他的namespace仍然是namespace sawzall。

现在文件末尾添加一个函数:

REGISTER_MODULE_INITIALIZER(

UrlDomainIntrinsic,

{REQUIRE_MODULE_INITIALIZED(Sawzall);  sawzall::Initialize();}

);

REGISTER_MODULE_INITIALIZER是向sawzall中注册钩子函数,让zawzall代码在启动的时候能够执行这里面的Inintialize函数,从而能把我们写的扩展函数暴露出来。每个扩展文件都要注册这个函数,这里再看看这个sawzall::Initialize()函数,因为这个宏是在代码的namespace sawzall外面执行的所以添加sawzall::。

static void Initialize() {

// make sure the SymbolTable is initialized

assert(SymbolTable::is_initialized());

Proc* proc = Proc::initial_proc();

 

// shortcuts for predefined types

Type* bool_type = SymbolTable::bool_type();

Type* float_type = SymbolTable::float_type();

Type* string_type = SymbolTable::string_type();                                  // 这里注册了一个函数 get_host_port,参数是string类型的

SymbolTable::RegisterIntrinsic("get_host_port",

FunctionType::New(proc)->

par("get_host_port", string_type)->

res(string_type),

get_host_port,

get_host_port_doc, Intrinsic::kNormal);

}

第一个参数是制定调用名称,第二个是制定调用的函数的参数类型,第三个是函数的具体实现,第四个是函数的一个说明,其实就是一个字符串,第五个参数是说明这个函数的类型,这个类型有以下三种:

enum Attribute

{

kNormal = 0 << 0,

kCanFold = 1 << 0// This intrinsic can be constant-folded.

kThreadSafe = 1 << 1// This intrinsic is thread-safe.

};

再来看看函数的实现:

static const char get_host_port_doc[] =  "Return host port of url"; /// 函数说明

static void get_host_port(Proc* proc, Val**&amp; sp)

{

string original_url = Engine::pop_cpp_string(proc, sp);    /// 这里从sawzall上层获取传入的参数

/// 这里开始处理参数,使用外部类接口

char* str_domain = NULL;

StringVal* szl_string = NULL;

static web::url::Url url;

url.Load(original_url.c_str(), original_url.length());

if (url.IsValid())     /// url类的有效判断

{

szl_string = Factory::NewStringCPP(proc, url.GetHostPort());

/// 装换为sawzall的string类型,它针对string和char有不同的函数来处理

}

else

{

szl_string = Factory::NewStringC(proc, "bad.site");

}

Engine::push(sp, szl_string);  ///这里再把这个处理后的结果放回sawzall上层

}   

这样扩展之后就可以在sawzall代码中直接调用get_host_port这个函数了。

例如我的sawzall代码是这样写的:

g_processor_map = function(data: bytes): int {

#get glable data from pb

log := falcon.DispatchServerCrawlResultLog(data);

url := string(log.request_log.url);

site := get_host_port(url); #在这里使用这个函数直接获取url对应的域名

。。。。。。

}

好了,总结记录到这里,此外我们还扩展了domian求聚合域名的方法,还扩展了sawzall的一个聚合器来输出同一个key下的多个value。这些以后再写出来。

看完本文有收获?请分享给更多人

关注「黑光技术」,关注大数据+微服务