2010-06-09 11 views
12

Prima volta Mappa/Riduci utente qui e utilizzando MongoDB. Ho un sacco di dati sulle visite di pagina che mi piacerebbe avere un senso usando Map/Reduce. Di seguito è fondamentalmente ciò che voglio fare, ma come un principiante totale una mappa/riduzione, penso che questo sia al di sopra delle mie conoscenze!Mongo Map Riduci la prima volta

  1. Passare attraverso tutte le pagine con visite negli ultimi 30 giorni e dove esterno = vero.
  2. Poi per ogni pagina, trovare tutte le visite
  3. Gruppo tutte le visite in base alla località di riferimento
  4. Per ogni posizione di riferimento, calcolare quanti poi è andato a visitare una pagina che ha un certo "tipo" e ha anche una certa parola nei "tag".

La banca dati e la raccolta sono organizzati come documento

$mongo->dbname->visits 

Un campione è:

{"url": "www.example.com", "type": "a", "refer": {"external": true, "domain": "twitter.com", "url": "http://www.twitter.com/page"}, "page": "1235", "user": "1232", "time": 1234567890} 

E poi vorrei trovare documenti di tipo B con un determinato tag.

{"url": "www.example.com", "type": "b", "page": "745", "user": "1232", "time": 1234567890, "tags": {"a", "b", "c"}} 

Sto usando la normale estensione Mongo PHP se questo ha un impatto.

+1

Quale struttura di database avete? Come sono organizzate le tue collezioni e i tuoi documenti? –

+0

Aggiunto al post precedente. Questo aiuto? – James

+0

OK, il documento di esempio non include un campo "referral", "external" o "tags". Quello che stai suggerendo è davvero complicato, quindi probabilmente dovrai mostrarci più di un documento. E probabilmente dovrai mostrarlo con tutti i dettagli. –

risposta

16

Ok, ho inventato qualcosa che io penso che possa fare quello che vuoi. Nota che questo potrebbe non funzionare esattamente dal momento che non sono sicuro al 100% del tuo schema (considerando i tuoi esempi mostrare refer disponibile nel tipo a, ma non b (non sono sicuro che sia un'omissione, o che cosa stai considerando di voler vista da referer) ... Ad ogni modo, ecco cosa mi è venuta in mente:

La funzione di mappa:

function() { 
    var obj = { 
     "types": {}, 
     "tags": {}, 
    } 
    obj.types[this.type] = 1; 
    if (this.tags) { 
     for (var tag in this.tags) { 
      obj.tags[this.tags[tag]] = 1; 
     } 
    } 
    emit(this.refer.url, obj); 
} 

La funzione di Riduzione:

function(key, values) { 
    var obj = { 
     "types": {}, 
     "tags": {}, 
    } 
    for (var i = 0; i < values.length; i++) { 
     for (var type in values[i].types) { 
      if (!type in obj.types) { 
       obj.types[type] = 0; 
      } 
      obj.types[type] += values[i].types[type]; 
     } 
     for (var tag in values[i].tags) { 
      if (!tag in obj.tags) { 
       obj.tags[tag] = 0; 
      } 
      obj.tags[tag] += values[i].tags[tag]; 
     } 
    } 
    return obj; 
} 

Quindi, in pratica, come funziona è questo: la funzione Map utilizza una chiave di riferimento.url (cosa ho indovinato in base alla tua desc ription). Quindi il risultato finale sarà simile a un array con _id uguale a refer.url (Si raggruppa in base all'URL). Quindi crea un oggetto che ha due oggetti sotto di esso (tipi e tag). La ragione per l'oggetto è che la mappa e la riduzione possono emettere lo stesso oggetto formato. A parte questo, penso che dovrebbe essere relativamente autoesplicativo (se non capisco, posso provare a spiegare di più) ...

Quindi implementiamo questo in PHP (supponendo che e $reduce siano stringhe con quanto sopra contenuto con loro per la durezza):

$mapFunc = new MongoCode($map); 
$reduceFunc = new MongoCode($reduce); 
$query = array(
    'time' => array('$gte' => time() - (60*60*60*24*30)), 
    'refer.external' => true 
); 
$collection = 'visits'; 
$command = array(
    'mapreduce' => $collection, 
    'map' => $mapFunc, 
    'reduce' => $reduceFunc, 
    'query' => $query, 
); 

$statsInfo = $db->command($command); 

$statsCollection = $db->selectCollection($sales['result']); 

$stats = $statsCollection->find(); 

foreach ($stats as $stat) { 
    echo $stats['_id'] .' Visited '; 
    foreach ($stats['value']['types'] as $type => $times) { 
     echo "Type $type $times Times, "; 
    } 
    foreach ($stats['value']['tags'] as $tag => $times) { 
     echo "Tag $tag $times Times, "; 
    } 
    echo "\n"; 
} 

Nota, non l'ho ancora testato. Questo è proprio quello che mi è venuta in mente in base alla mia comprensione dello schema, e dalla mia comprensione di Mongo e la sua attuazione Map-Reduce ...

+0

$ statsCollection = $ db-> selectCollection ($ sales ['result']); $ vendite? – Tobias

Problemi correlati