【发布时间】:2016-02-20 02:17:45
【问题描述】:
我正在编写一个 UDF 来处理 Google Analytics 数据,并在我尝试处理多行时收到“UDF 内存不足”错误消息。我下载了原始数据并找到了最大的记录,并尝试在其上运行我的 UDF 查询,并成功。一些行有多达 500 个嵌套命中,命中记录的大小(到目前为止,原始 GA 数据的每一行的最大组成部分)似乎确实会影响我在收到错误之前可以处理多少行.
例如查询
select
user.ga_user_id,
ga_session_id,
...
from
temp_ga_processing(
select
fullVisitorId,
visitNumber,
...
from [79689075.ga_sessions_20160201] limit 100)
返回错误,但是
from [79689075.ga_sessions_20160201] where totals.hits = 500 limit 1)
没有。
我的印象是任何内存限制都是每行的?我尝试了几种技术,例如在emit(return_dict); 之前设置row = null;(其中return_dict 是处理后的数据)但无济于事。
UDF 本身并没有做任何花哨的事情;我会把它贴在这里,但它的长度约为 45 kB。它基本上做了很多事情:
function temp_ga_processing(row, emit) {
topic_id = -1;
hit_numbers = [];
first_page_load_hits = [];
return_dict = {};
return_dict["user"] = {};
return_dict["user"]["ga_user_id"] = row.fullVisitorId;
return_dict["ga_session_id"] = row.fullVisitorId.concat("-".concat(row.visitNumber));
for(i=0;i<row.hits.length;i++) {
hit_dict = {};
hit_dict["page"] = {};
hit_dict["time"] = row.hits[i].time;
hit_dict["type"] = row.hits[i].type;
hit_dict["page"]["engaged_10s"] = false;
hit_dict["page"]["engaged_30s"] = false;
hit_dict["page"]["engaged_60s"] = false;
add_hit = true;
for(j=0;j<row.hits[i].customMetrics.length;j++) {
if(row.hits[i].customDimensions[j] != null) {
if(row.hits[i].customMetrics[j]["index"] == 3) {
metrics = {"video_play_time": row.hits[i].customMetrics[j]["value"]};
hit_dict["metrics"] = metrics;
metrics = null;
row.hits[i].customDimensions[j] = null;
}
}
}
hit_dict["topic"] = {};
hit_dict["doctor"] = {};
hit_dict["doctor_location"] = {};
hit_dict["content"] = {};
if(row.hits[i].customDimensions != null) {
for(j=0;j<row.hits[i].customDimensions.length;j++) {
if(row.hits[i].customDimensions[j] != null) {
if(row.hits[i].customDimensions[j]["index"] == 1) {
hit_dict["topic"] = {"name": row.hits[i].customDimensions[j]["value"]};
row.hits[i].customDimensions[j] = null;
continue;
}
if(row.hits[i].customDimensions[j]["index"] == 3) {
if(row.hits[i].customDimensions[j]["value"].search("doctor") > -1) {
return_dict["logged_in_as_doctor"] = true;
}
}
// and so on...
}
}
}
if(row.hits[i]["eventInfo"]["eventCategory"] == "page load time" && row.hits[i]["eventInfo"]["eventLabel"].search("OUTLIER") == -1) {
elre = /(?:onLoad|pl|page):(\d+)/.exec(row.hits[i]["eventInfo"]["eventLabel"]);
if(elre != null) {
if(parseInt(elre[0].split(":")[1]) <= 60000) {
first_page_load_hits.push(parseFloat(row.hits[i].hitNumber));
if(hit_dict["page"]["page_load"] == null) {
hit_dict["page"]["page_load"] = {};
}
hit_dict["page"]["page_load"]["sample"] = 1;
page_load_time_re = /(?:onLoad|pl|page):(\d+)/.exec(row.hits[i]["eventInfo"]["eventLabel"]);
if(page_load_time_re != null) {
hit_dict["page"]["page_load"]["page_load_time"] = parseFloat(page_load_time_re[0].split(':')[1])/1000;
}
}
// and so on...
}
}
row = null;
emit return_dict;
}
作业ID是realself-main:bquijob_4c30bd3d_152fbfcd7fd
【问题讨论】:
-
1. JavaScript 处理环境对每个查询的可用内存有限。累积过多本地状态的 UDF 查询可能会因内存耗尽而失败; 2. 处理单行时,UDF 输出的数据量应在 5 Mb 左右或更少; 3. 您可能需要提供您的 UDF 代码
-
@MikhailBerlyant 是的,我知道这些事情(在我开始写这篇文章之前,我曾多次阅读 Google 的 UDF 页面)。我在上面提到过,我在最大的一行上进行了尝试,这表明我每行返回
-
@Grayson :我不得不从示例中修改您的代码以使其运行(我无权访问您的 GCS 存储桶中的代码) - 但是这个示例确实适用于我在飞行中的更改。当更改在生产中时,我会在这里再次更新。
标签: google-bigquery