MongoDB mapreduce에서 values 객체를 평탄화하려면 어떻게 해야 합니까?
MongoDB를 사용하여 Apache 로그 파일을 분석하려고 합니다.다음을 만들었습니다.receipts
Apache 액세스 로그에서 수집합니다.다음은 제 모델의 개요입니다.
db.receipts.findOne()
{
"_id" : ObjectId("4e57908c7a044a30dc03a888"),
"path" : "/videos/1/show_invisibles.m4v",
"issued_at" : ISODate("2011-04-08T00:00:00Z"),
"status" : "200"
}
나는 모든 데이터를 다음 기준으로 그룹화하는 MapReduce 함수를 작성했습니다.issued_at
날짜 필드.총 요청 수를 요약하고 각 고유 경로에 대한 요청 수를 분석합니다.다음은 출력의 예입니다.
db.daily_hits_by_path.findOne()
{
"_id" : ISODate("2011-04-08T00:00:00Z"),
"value" : {
"count" : 6,
"paths" : {
"/videos/1/show_invisibles.m4v" : {
"count" : 2
},
"/videos/1/show_invisibles.ogv" : {
"count" : 3
},
"/videos/6/buffers_listed_and_hidden.ogv" : {
"count" : 1
}
}
}
}
대신 출력을 다음과 같이 표시하려면 어떻게 해야 합니까?
{
"_id" : ISODate("2011-04-08T00:00:00Z"),
"count" : 6,
"paths" : {
"/videos/1/show_invisibles.m4v" : {
"count" : 2
},
"/videos/1/show_invisibles.ogv" : {
"count" : 3
},
"/videos/6/buffers_listed_and_hidden.ogv" : {
"count" : 1
}
}
}
현재는 불가능하지만, 저는 이 경우에 투표할 것을 제안합니다: https://jira.mongodb.org/browse/SERVER-2517 .
이전 답변과 의견을 최대한 활용합니다.
db.items.find().hint({_id: 1}).forEach(function(item) {
db.items.update({_id: item._id}, item.value);
});
http://docs.mongodb.org/manual/core/update/ #에서 기존 버전을 새 버전으로 교체
"만약에update
인수에는 필드 및 값 쌍만 포함됩니다.update()
메소드는 기존 문서를 의 문서로 대체합니다.update
인수, 제외_id
"현장."
그래서 당신은 둘 다 할 필요가 없습니다.$unset value
각 필드를 나열할 수 없습니다.
https://docs.mongodb.com/manual/core/read-isolation-consistency-recency/ #cisco-messages에서 "MongoDB 커서는 일부 상황에서 동일한 문서를 두 번 이상 반환할 수 있습니다. ...쿼리가 각 문서를 두 번 이상 반환하지 않도록 이 필드 또는 이 필드에 고유 색인을 사용합니다.hint()를 사용하여 쿼리가 해당 인덱스를 사용하도록 명시적으로 강제합니다."
AFAIK, 설계상 Mongo의 맵 축소는 "값 튜플"로 결과를 뱉을 것이고 저는 그 "출력 형식"을 구성할 어떤 것도 보지 못했습니다.final() 방법을 사용할 수 있습니다.
다음을 사용하여 데이터를 재구성하는 사후 프로세스를 실행할 수 있습니다.
results.find({}).forEach( function(result) {
results.update({_id: result._id}, {count: result.value.count, paths: result.value.paths})
});
네, 보기 흉해요.알고있어요.
수집 참조를 사용하여 Dan의 코드를 수행할 수 있습니다.
function clean(collection) {
collection.find().forEach( function(result) {
var value = result.value;
delete value._id;
collection.update({_id: result._id}, value);
collection.update({_id: result.id}, {$unset: {value: 1}} ) } )};
@ljonas와 유사한 접근 방식이지만 문서 필드를 하드 코딩할 필요는 없습니다.
db.results.find().forEach( function(result) {
var value = result.value;
delete value._id;
db.results.update({_id: result._id}, value);
db.results.update({_id: result.id}, {$unset: {value: 1}} )
} );
제안된 모든 솔루션은 최적의 솔루션과는 거리가 먼 솔루션입니다.지금까지 할 수 있는 가장 빠른 방법은 다음과 같습니다.
var flattenMRCollection=function(dbName,collectionName) {
var collection=db.getSiblingDB(dbName)[collectionName];
var i=0;
var bulk=collection.initializeUnorderedBulkOp();
collection.find({ value: { $exists: true } }).addOption(16).forEach(function(result) {
print((++i));
//collection.update({_id: result._id},result.value);
bulk.find({_id: result._id}).replaceOne(result.value);
if(i%1000==0)
{
print("Executing bulk...");
bulk.execute();
bulk=collection.initializeUnorderedBulkOp();
}
});
bulk.execute();
};
그럼 다음과 같이 부르세요.flattenMRCollection("MyDB","MyMRCollection")
이것은 순차적 업데이트보다 훨씬 빠릅니다.
빈센트의 대답을 실험하던 중 몇 가지 문제점을 발견했습니다.기본적으로 각 루프 내에서 업데이트를 수행하면 문서가 컬렉션의 끝으로 이동하고 커서가 해당 문서에 다시 도달합니다(예).$snapshot을 사용하면 이 문제를 피할 수 있습니다.따라서 아래에 자바의 예를 제공합니다.
final List<WriteModel<Document>> bulkUpdate = new ArrayList<>();
// You should enable $snapshot if performing updates within foreach
collection.find(new Document().append("$query", new Document()).append("$snapshot", true)).forEach(new Block<Document>() {
@Override
public void apply(final Document document) {
// Note that I used incrementing long values for '_id'. Change to String if
// you used string '_id's
long docId = document.getLong("_id");
Document subDoc = (Document)document.get("value");
WriteModel<Document> m = new ReplaceOneModel<>(new Document().append("_id", docId), subDoc);
bulkUpdate.add(m);
// If you used non-incrementing '_id's, then you need to use a final object with a counter.
if(docId % 1000 == 0 && !bulkUpdate.isEmpty()) {
collection.bulkWrite(bulkUpdate);
bulkUpdate.removeAll(bulkUpdate);
}
}
});
// Fixing bug related to Vincent's answer.
if(!bulkUpdate.isEmpty()) {
collection.bulkWrite(bulkUpdate);
bulkUpdate.removeAll(bulkUpdate);
}
참고: 이 스니펫은 100k 레코드와 14개의 속성(IMDB 데이터 세트)을 가진 내 컴퓨터에서 실행하는 데 평균 7.4초가 걸립니다.배치하지 않으면 평균 25.2초가 소요됩니다.
언급URL : https://stackoverflow.com/questions/7257989/in-mongodb-mapreduce-how-can-i-flatten-the-values-object
'programing' 카테고리의 다른 글
SQL 서버에 파일이 있는지 확인하시겠습니까? (0) | 2023.07.02 |
---|---|
Windows 7(윈도우 7)에서 폴더에 쓰기 위한 ASP.NET 권한을 부여하려면 어떻게 해야 합니까? (0) | 2023.07.02 |
응용프로그램에 "암호화 포함"이 있습니까? (0) | 2023.07.02 |
유형 스크립트를 사용하여 상태 후크 사용에서 받은 배열 표시 (0) | 2023.07.02 |
새로운 문자열을 만들지 않고 루비에서 문자열을 트리밍하는 표준 방법은 무엇입니까? (0) | 2023.07.02 |