AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 146510
Accepted
Azwok
Azwok
Asked: 2016-08-12 04:12:50 +0800 CST2016-08-12 04:12:50 +0800 CST 2016-08-12 04:12:50 +0800 CST

erros de saída mapReduce somente quando maior consulta de seleção de entrada

  • 772

Por favor, você pode ajudar a identificar por que este mapReduce está falhando (algumas vezes) e propor como garantir que funcione o tempo todo?

Estou usando o mapReduce do MongoDB para realizar o agrupamento de valores de matriz por datas e, em seguida, determinar o valor médio em cada data. Isso geralmente está funcionando bem, no entanto, estou descobrindo que alguns pontos estão falhando, com o mapa reduzido retornando valores "nan" e não consigo descobrir o porquê. O que é mais estranho é que, embora os pontos que falham sejam consistentes se eu executar novamente a função, eles nem sempre falham quando eu executo o map-reduce em menos números de documentos, mesmo que os documentos que vão para o grupo específico que falhar não mudará. Espero que as figuras abaixo esclareçam o que quero dizer.

Dada uma carga de pontos em um mapa (pontos), a função de mapa os agrupa em caixas com base em sua localização. Cada ponto tem uma matriz de datas e valores. A função de redução soma esses valores em cada data e a função de finalização calcula o valor médio de cada data, fornecendo um valor médio para cada quadrado no mapa.

Figura 1. Pontos agrupados em quadrados, onde o ponto vermelho (e possivelmente rosa, embora esteja no limite) não foi adicionado.

O exemplo da Figura 1. (não é o mesmo quadrado da Figura 2. e 3.) mostra o que quero dizer com relação ao erro e, embora o ponto no círculo vermelho certamente deva estar dentro desse quadrado (o quadrado não verde), a função mapReduce errou aqui e falhou ao adicionar o ponto.

Para demonstrar o comportamento inconsistente, abaixo mostro a função de redução de mapa executada em uma pequena área de uma cidade.

Figura 2. Função mapReduce funcionando bem em uma pequena área, caixa vermelha desenhada para indicar o quadrado do problema.

Aqui está a função mapReduce idêntica executada em um subconjunto menor de my, que foi obtido modificando a função query: {$geoWithin...} para selecionar apenas documentos dentro de um pequeno polígono que caiba na figura. A próxima figura é a mesma função mapReduce , mas com a seleção de consulta :{$geoWithin} 1/8 do Reino Unido, mostrada como no quadrado vermelho da Figura 4.

Figura 3. Mesma função mapReduce usada na Figura 2, mas agora com um erro no somatório.

Como pode ser visto na Figura 3, a maioria dos quadrados foi bem processada e produziu o mesmo resultado. No entanto, há um quadrado mostrado aqui (e vários outros em outros lugares), que falhou e, ao consultar a saída do mapReduce , eles resultam em valores "nan".

Com a versão de trabalho, o documento na caixa vermelha se parece com:

{                                                               
    "_id" : "18_129961_84424",                              
    "geometry" : {                                          
        "type" : "Polygon",                             
        "coordinates" : [[                                       
                [-1.525726318359375, 53.79335064315454],
                [-1.525726318359375, 53.794161837371036],
                [-1.52435302734375, 53.794161837371036],
                [-1.52435302734375, 53.79335064315454],
                [-1.525726318359375, 53.79335064315454]
            ]]
    },
    "properties" : [
        {
            "date" : ISODate("2015-08-15T00:00:00Z"),
            "sum" : -9.486295223236084,
            "points" : 4,
            "displace" : -2.371573805809021
        }
    ]
}

Considerando que na versão quebrada, o mesmo documento se parece com:

{                                                               
    "_id" : "18_129961_84424",                              
    "geometry" : {                                          
        "type" : "Polygon",                             
        "coordinates" : [[                                       
                [-1.525726318359375, 53.79335064315454],
                [-1.525726318359375, 53.794161837371036],
                [-1.52435302734375, 53.794161837371036],
                [-1.52435302734375, 53.79335064315454],
                [-1.525726318359375, 53.79335064315454]
            ]]
    },
    "properties" : [
        {
            "date" : ISODate("2015-08-15T00:00:00Z"),
            "sum" : NaN,
            "points" : 3,
            "displace" : NaN
        }
    ]
}

O fato de que esse quadrado pode processar às vezes significa que não duvido dos dados, mas algo está acontecendo na função mapReduce . Os quatro pontos que devem ter sido somados corretamente são:

{ "_id" : ObjectId("57a888d4c7afa6e97e7fe00c"), "geometry" : { "type" : "Point", "coordinates" : [ -1.5254854131489992, 53.79415290802717 ] }, "properties" : [ { "date" : ISODate("2015-08-15T00:00:00Z"), "displace" : -2.3721842765808105 } ] }
{ "_id" : ObjectId("57a888d4c7afa6e97e7fe37a"), "geometry" : { "type" : "Point", "coordinates" : [ -1.5254854131489992, 53.79335290752351 ] }, "properties" : [ { "date" : ISODate("2015-08-15T00:00:00Z"), "displace" : -2.382347822189331 } ] }
{ "_id" : ObjectId("57a888d4c7afa6e97e7fe37b"), "geometry" : { "type" : "Point", "coordinates" : [ -1.52468541264534, 53.79335290752351 ] }, "properties" : [ { "date" : ISODate("2015-08-15T00:00:00Z"), "displace" : -2.372774124145508 } ] }
{ "_id" : ObjectId("57a888d4c7afa6e97e7fe00d"), "geometry" : { "type" : "Point", "coordinates" : [ -1.52468541264534, 53.79415290802717 ] }, "properties" : [ { "date" : ISODate("2015-08-15T00:00:00Z"), "displace" : -2.3589890003204346 } ] }

Suspeito que possa ser um problema na minha função Reduce não ser idempotente, conforme proposto na resposta ao MongoDB MapReduce retornando resultados inesperados e agrupando duas vezes , mas não tenho certeza se isso é verdade e, em caso afirmativo, não tenho certeza de como para garantir que é idempotente neste caso. Para completar, incluo minha função mapReduce real abaixo.

var map = function(){
    function lon2tile (lon, zoom){ return Math.floor((lon+180)/360*Math.pow(2,zoom)); }
    function lat2tile (lat, zoom){ return Math.floor((1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,zoom)); }
    function tile2long(x,z) { return (x/Math.pow(2,z)*360-180); }
    function tile2lat(y,z) {
        var n=Math.PI-2*Math.PI*y/Math.pow(2,z);
        return (180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n))));
    }
    function tile2poly(x, y, z){
        xl = tile2long(x, z);
        yt = tile2lat(y,z);
        xr = tile2long(x+1,z);
        yb = tile2lat(y+1,z);
        poly = [[
            [xl, yb],
            [xl, yt],
            [xr, yt],
            [xr, yb],
            [xl, yb]
        ]];
        return poly
    }

    var zoom = 18;
    var lon = this.geometry.coordinates[0];
    var lat = this.geometry.coordinates[1];
    var xtile = lon2tile(lon, zoom);
    var ytile = lat2tile(lat, zoom);

    var key = zoom+'_'+xtile+'_'+ytile;
    var poly = tile2poly(xtile, ytile, zoom);

    var value = {
        geometry: {type: 'Polygon', coordinates: poly},
        properties: this.properties
    };

    for(var idx=0; idx< value.properties.length; idx++){
        value.properties[idx].points = 1;
    };

    emit (key, value);
}


var reduce = function(mapKey, mapVal){
    redVal = {
        "geometry" : mapVal[0].geometry,
        "properties": []
    };

    for(var idx=0; idx< mapVal.length; idx++){
        for(var pidx=0; pidx< mapVal[idx].properties.length; pidx++){
            loc = -1;
            for (var el=0; el<redVal.properties.length; el++){
                if(redVal.properties[el].date.toISOString() == mapVal[idx].properties[pidx].date.toISOString()){
                    loc = el;
                    break;
                }
            }

            if (loc == -1){
                redVal.properties.push({'date': mapVal[idx].properties[pidx].date,
                                        'sum': mapVal[idx].properties[pidx].displace,
                                        'points': 1});
            }
            else{
                redVal.properties[loc].sum += mapVal[idx].properties[pidx].displace;
                redVal.properties[loc].points += mapVal[idx].properties[pidx].points;
            }
        }
    };

    return redVal;
}

var final = function(redKey, redVal){
    for (var el=0; el<redVal.properties.length; el++){
        if (!("sum" in redVal.properties[el])){
            redVal.properties[el].sum = redVal.properties[el].displace;
        }

        redVal.properties[el].displace = redVal.properties[el].sum / redVal.properties[el].points;
    } 

    return redVal;
}

var query_in = {
    'geometry': {
        '$geoIntersects': {
            '$geometry': {
                'type': 'Polygon',
                'coordinates': [[
                    [-2.8125, 53.33087298301705],
                    [-2.8125, 54.1624339680678],
                    [-1.40625, 54.1624339680678],
                    [-1.40625, 53.33087298301705],
                    [-2.8125, 53.33087298301705]
                ]]                            
            }
        }
    }
}

db.c0.mapReduce(map, reduce, {out: "mrTest", query:query_in, finalize:final})

Após uma investigação mais aprofundada, vejo que esses erros estão aparecendo apenas perto do final do processo de redução do mapa (veja a imagem abaixo). Os dados que serão selecionados na etapa de consulta mapReduce são todos os pontos dentro da caixa vermelha. O espaço para a borda direita é excluído, pois não há dados lá.

Figura 4. Cobertura do Reino Unido, mostrando o ponto perdido mais ao sul.


Depois de fazer uma investigação mais aprofundada do único quadrado do problema na Figura 3, posso ver que a parte do mapa está agrupando corretamente 4 pontos. Isso foi obtido construindo um array durante a fase de redução, onde cada valor mapeado é inserido em um array toda vez que é chamado. Isso mostra pontos nas fases de redução que falham, embora eu não consiga entender o porquê.

Modificando a função de redução para: function(mapKey, mapVal){ redVal = { "all_mapped": [], "geometry" : mapVal[0].geometry, "properties": [] };

    for(var idx=0; idx< mapVal.length; idx++){
        redVal.all_mapped.push({'iter':idx, 'map': mapVal[idx]});
        for(var pidx=0; pidx< mapVal[idx].properties.length; pidx++){
            var loc = -1;
            for (var el=0; el<redVal.properties.length; el++){
                if(redVal.properties[el].date.toISOString() === mapVal[idx].properties[pidx].date.toISOString()){
                    loc = el;
                    break;
                }
            }

            if (loc === -1){
                redVal.properties.push({'date': mapVal[idx].properties[pidx].date,
                                        'sum': mapVal[idx].properties[pidx].displace,
                                        'points': mapVal[idx].properties[pidx].points});
            }
            else{
                redVal.properties[loc].sum += mapVal[idx].properties[pidx].displace;
                redVal.properties[loc].points += mapVal[idx].properties[pidx].points;
            }
        }
    };

    return redVal;
};

é possível ver na saída que a função de redução é chamada duas vezes. Na primeira vez, ele possui 3 valores mapeados que são somados corretamente. Em seguida, a função de redução é chamada uma segunda vez para combinar a saída reduzida anteriormente com o 1 ponto adicional. Eu acredito que é aqui que a soma falha.

mongodb mongodb-3.2
  • 2 2 respostas
  • 400 Views

2 respostas

  • Voted
  1. David Hyman
    2016-08-14T06:22:19+08:002016-08-14T06:22:19+08:00

    Uma variedade de coisas que eu tentaria:

    • Os polígonos estão usando flutuadores, é possível que os ladrilhos x/y estejam errados para alguns pontos devido a erros de arredondamento inerentes a esse tipo de dados (embora eu não veja por que isso não seria idempotente).
    • Corridas de buracos parecem seguir lats em vez de lons, então isso aponta mais para algo relacionado ao código do que ao banco de dados (espera-se que qualquer estranheza do banco de dados seja lat/lon igualmente).
    • Você pode verificar a exatidão do seu mapa e reduzir as funções? Poderia escrever testes de unidade para casos primários e secundários.
    • Em sua redução, seu locnão é var'd - é possível que este global possa ser acessado por executores paralelos?
    • Datea comparação deve usar ===- e eles definitivamente não são atualizados automaticamente nem nada - poderia mudar em uma sessão mais longa de redução de mapa?
    • Mais instruções de depuração/impressão para registrar estados intermediários para os blocos com falha; https://stackoverflow.com/questions/13963483/how-to-get-print-output-for-debugging-map-reduce-in-mongoid
    • Para desempenho, transmita funções no escopo em vez de defini-las em cada mapa; https://stackoverflow.com/questions/7273379/how-to-use-variables-in-mongodb-map-reduce-map-function
    • 2
  2. Best Answer
    Azwok
    2016-08-16T02:35:50+08:002016-08-16T02:35:50+08:00

    Desde a minha última edição onde identifiquei a função reduce sendo chamada duas vezes, encontrei o erro no mapReduce , que é o seguinte.

    Como a função de redução é chamada duas vezes, a saída da primeira chamada resulta em uma saída do seguinte objeto reduzido:

    reducedValue: {
        "geometry" : {
            "type" : "Polygon",
            "coordinates" : [[[...]]]
        },
        "properties" : [
            {
                "date" : ISODate("2015-08-15T00:00:00Z"),
                "sum" : -7.177929162979126,
                "points" : 3
            }
        ]
    }
    

    Este objeto não contém o campo " properties.displace ". Portanto, quando a função de redução for chamada novamente, ela está passando neste objeto acima, portanto, no ponto na função de redução onde o campo " properties.displace " é adicionado ao valor " properties.sum ", o código apresentará um erro.

    Para resolver esse problema, atualizei o mapReduce para que a função map também gere um campo " properties.sum " que é igual em valor ao campo " properties.displace ", então a fase de redução soma todas as " properties.sum " valores, de modo que, mesmo que execute a função de redução várias vezes, todos os campos existam e contenham os valores acumulados apropriados. O mapReduce completo agora é o seguinte:

    Mapa

    var map = function(){
        function lon2tile (lon, zoom){ return Math.floor((lon+180)/360*Math.pow(2,zoom)); }
        function lat2tile (lat, zoom){ return Math.floor((1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,zoom)); }
        function tile2long(x,z) { return (x/Math.pow(2,z)*360-180); }
        function tile2lat(y,z) {
            var n=Math.PI-2*Math.PI*y/Math.pow(2,z);
            return (180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n))));
        }
        function tile2poly(x, y, z){
            xl = tile2long(x, z);
            yt = tile2lat(y,z);
            xr = tile2long(x+1,z);
            yb = tile2lat(y+1,z);
            poly = [[
                [xl, yb],
                [xl, yt],
                [xr, yt],
                [xr, yb],
                [xl, yb]
            ]];
            return poly
        }
    
        var zoom = 18;
        var lon = this.geometry.coordinates[0];
        var lat = this.geometry.coordinates[1];
        var xtile = lon2tile(lon, zoom);
        var ytile = lat2tile(lat, zoom);
    
        var key = zoom+'_'+xtile+'_'+ytile;
        var poly = tile2poly(xtile, ytile, zoom);
    
        var value = {
            geometry: {type: 'Polygon', coordinates: poly},
            properties: this.properties
        };
    
        for(var idx=0; idx< value.properties.length; idx++){
            value.properties[idx].points = 1;
            value.properties[idx].sum = value.properties[idx].displace;
        };
    
        emit (key, value);
    }
    

    Reduzir

    var reduce = function(mapKey, mapVal){
        function(mapKey, mapVal){
            redVal = {
                "geometry" : mapVal[0].geometry,
                "properties": []
            };
    
            for(var idx=0; idx< mapVal.length; idx++){
                for(var pidx=0; pidx< mapVal[idx].properties.length; pidx++){
                    var loc = -1;
                    for (var el=0; el<redVal.properties.length; el++){
                        if(redVal.properties[el].date.toISOString() === mapVal[idx].properties[pidx].date.toISOString()){
                            loc = el;
                            break;
                        }
                    }
    
                    if (loc === -1){
                        redVal.properties.push(mapVal[idx].properties[pidx]);
                    }
                    else{
                        redVal.properties[loc].sum += mapVal[idx].properties[pidx].sum;
                        redVal.properties[loc].points += mapVal[idx].properties[pidx].points;
                    }
                }
            };
    
            return redVal;
        };
    }
    
    • 0

relate perguntas

  • Mongo Map-Reduce ou Sharding?

  • Configurando o Mongo com clustering

  • Diferença entre as chamadas find e findone do MongoDB

  • A fragmentação é eficaz para coleções pequenas?

  • Bons recursos para operar/administrar o MongoDB

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve