2011-01-27 36 views
7

Tôi cố gắng để tính toán giá trị trung bình từ một bộ sưu tập sử dụng trình điều khiển MongoDB java, như thế này:làm thế nào để tính toán mức trung bình với MongoDB và NumberLong

DBObject condition = 
    new BasicDBObject("pluginIdentifier", plugin.getIdentifier()); 

DBObject initial = new BasicDBObject(); 

initial.put("count", 0); 
initial.put("totalDuration", 0); 
String reduce = "function(duration, out) { out.count++; 
    out.totalDuration+=duration.floatApprox; }"; 
String finalize = "function(out) { out.avg = out.totalDuration.floatApprox/
    out.count; }"; 

DBObject avg = durationEntries.group(
    new BasicDBObject("pluginIdentifier", true), 
    condition, initial, reduce, finalize); 

System.out.println(avg); 

"duration" là một NumberLong (trong java, nó là một Long, có lẽ trình điều khiển java chuyển đổi nó). tôi đã tìm ra sau khi một số tìm kiếm rằng để trích xuất số lượng, sử dụng .floatApprox là một con đường để đi, và điều này cũng làm việc trong MongoDB console:

> db.DurationEntries.findOne().duration.floatApprox 
5 

Tuy nhiên, chạy các mã java trên sẽ không tính trung bình, nhưng trả lại giá trị này thay vì

[{"pluginIdentifier":"dummy", "count":7.0, "totalDuration":NaN, "avg":NaN}] 

Tôi đã thử một số biến thể, có và không có .floatApprox, nhưng chỉ có thể nhận được một số chuỗi nối lạ cho đến bây giờ.

Câu hỏi của tôi là: Tôi đang làm gì sai/tôi nên tính toán mức trung bình của một cột NumberLong như thế nào?

+1

Chìa khóa ở đây mà bạn muốn làm cho mongo làm trung bình hơn là kéo dữ liệu cột vào Java? Bạn có chắc chắn bạn không vô tình có bất kỳ dữ liệu nào không phải là số trong khoảng thời gian của bạn không? –

+0

Vâng, đó là ý định của tôi, để thực hiện tính toán trong cơ sở dữ liệu chứ không phải trong bộ nhớ (bởi vì khi tôi sẽ có rất nhiều mục, tôi nghĩ rằng JVM của tôi sẽ hết bộ nhớ). Và thực sự có thể có dữ liệu không phải là số vì có thể có các mục trung bình "null" - tôi sẽ kiểm tra rằng –

+2

Nếu tất cả những gì bạn muốn là trung bình, thì tôi không nên dùng một lượng lớn bộ nhớ, không cần phải giữ từng mục trong bộ nhớ, chỉ là tổng số và tổng số. Tôi không quen thuộc với Mongo để nói chính xác như thế nào, nhưng nếu bạn có thể bó kết quả thiết lập từ truy vấn sau đó bạn có thể xử lý một tập hợp con tại một thời điểm. –

Trả lời

6

Nếu bạn đang gặp vấn đề với bản đồ/giảm, bạn có thể rơi xuống bảng điều khiển mongodb, làm việc đó ra và sau đó dịch nó vào trình điều khiển của bạn.

Lấy ví dụ, các tài liệu sau:

db.tasks.find() 
{ "_id" : ObjectId("4dd51c0a3f42cc01ab0e6506"), "duration" : 10, "name" : "StartProcess", "date" : "20110501" } 
{ "_id" : ObjectId("4dd51c0e3f42cc01ab0e6507"), "duration" : 11, "name" : "StartProcess", "date" : "20110502" } 
{ "_id" : ObjectId("4dd51c113f42cc01ab0e6508"), "duration" : 12, "name" : "StartProcess", "date" : "20110503" } 

Bạn sẽ viết MapReduce để tính toán thời gian trung bình của StartProcess như sau:

m = function(){ 
    emit(this.name , { totalDuration : this.duration , num : 1 }); 
}; 

r = function (name, values){ 
    var n = {totalDuration : 0, num : 0}; 
    for (var i=0; i<values.length; i++){ 
    n.totalDuration += values[i].totalDuration; 
    n.num += values[i].num; 
    } 
    return n; 
}; 

f = function(who, res){ 
    res.avg = res.totalDuration/res.num; 
    return res; 
}; 

Sau đó, giả sử bạn đang sử dụng MongoDB 1.7 hoặc cao hơn:

db.tasks.mapReduce(m, r, { finalize : f, out : {inline : 1} }); 

Sẽ cung cấp cho bạn câu trả lời sau:

"results" : [ 
    { 
    "_id" : "StartProcess", 
     "value" : { 
     "totalDuration" : 33, 
     "num" : 3, 
     "avg" : 11 
     } 
    } 
] 

Nếu điều này không hiệu quả, bạn có thể đăng chức năng bản đồ và cấu trúc tài liệu của mình không.

+0

cảm ơn! cuối cùng đã có thời gian để quay lại mã đó và thử nó! –

Các vấn đề liên quan