Tri Des Vues CouchDB Par Valeur

je teste CouchDB pour voir comment il pourrait gérer la journalisation de certains résultats de recherche. Ce que j'aimerais faire, c'est produire une vue où je peux produire les principales requêtes à partir des résultats. En ce moment, j'ai quelque chose comme ceci:

exemple de portion de document

{
  "query": "+dangerous +dogs",
  "hits": "123"
}

fonction de carte (Pas exactement ce dont j'ai besoin/envie, mais c'est assez bon pour les tests)

function(doc) {
  if (doc.query) {
    var split = doc.query.split(" ");
    for (var i in split) {
      emit(split[i], 1);
    }
  }
}

Fonction De Réduction

"
function (key, values, rereduce) {
  return sum(values);
}

maintenant cela me donnera des résultats dans un format où un terme de requête est la clé et le compte pour ce terme à droite, ce qui est grand. Mais j'aimerais que ce soit la valeur, pas la clé. D'après les sons, ce n'est pas encore possible avec CouchDB.

est-ce que quelqu'un a une idée de comment je peux obtenir une vue où j'ai une version commandée des termes de requête et leurs comptes connexes? Je suis très nouveau pour CouchDB et moi, Je ne vois pas comment j'écrirais les fonctions nécessaires.

36
demandé sur Lee Theobald 2010-05-12 14:00:52

7 réponses

il est vrai qu'il n'y a pas de réponse toute simple. Il existe toutefois plusieurs modèles.

  1. http://wiki.apache.org/couchdb/View_Snippets#Retrieve_the_top_N_tags . Personnellement, je n'aime pas cela parce qu'ils reconnaissent qu'il s'agit d'une solution fragile et que le code n'est pas relaxant.

  2. la réponse D'Avi, qui est de trier en mémoire dans votre application.

  3. couchdb-lucene ce dont tout le monde semble avoir besoin!

  4. ce que J'aime C'est ce que Chris a dit dans la citation D'Avi. Détendre. Dans CouchDB, les bases de données sont légères et excellent à vous donner une perspective unique de vos données. Ces jours-ci, le buzz est tout au sujet de la réplication filtrée qui est tout au sujet de découper des sous-ensembles de vos données à mettre dans un DB séparé.

    de toute façon, les bases sont simples. Vous prenez votre .rows de la sortie de vue et vous l'insérez dans un DB séparé qui émet tout simplement keyed sur le compte. Une astuce supplémentaire est d'écrire une fonction très simple _list . Listes" render " la sortie raw couch dans différents formats. Votre fonction _list devrait afficher

    { "docs":
        [ {..view row1...},
          {..view row2...},
          {..etc...}
        ]
    }
    

    ce que cela va faire est de formater la sortie de la vue exactement comme L'API _bulk_docs l'exige. Maintenant vous pouvez Piper curl directement dans une autre boucle:

    curl host:5984/db/_design/myapp/_list/bulkdocs_formatter/query_popularity \
     | curl -X POST host:5984/popularity_sorter/_design/myapp/_view/by_count
    
  5. en fait, si votre fonction de liste peut gérer tous les documents, vous pouvez simplement les trier et les retourner au client triés.

23
répondu JasonSmith 2010-05-12 18:17:16

Ce vint sur le CouchDB-user mailing liste, et Chris Anderson, l'un des principaux développeurs, a écrit:

c'est une requête courante, mais pas prise en charge directement par CouchDB vues -- pour ce faire, vous aurez besoin de copier le groupe-réduire la requête de une autre base de données, et construisez une vue pour trier par valeur.

c'est un compromis que nous faisons en faveur des requêtes de portée dynamique et indices incrémentiels.

j'avais besoin de le faire récemment, et j'ai fini par le faire dans mon application de niveau. Cela est facile à faire en JavaScript:

db.view('mydesigndoc', 'myview', {'group':true}, function(err, data) {

    if (err) throw new Error(JSON.stringify(err));

    data.rows.sort(function(a, b) {
        return a.value - b.value;
    });

    data.rows.reverse(); // optional, depending on your needs

    // do something with the data…
});

cet exemple s'exécute dans le noeud .js et utilise des nœud-couchdb , mais il peut facilement être adapté pour fonctionner dans un navigateur ou un autre environnement JavaScript. Et bien sûr, le concept est portable pour n'importe quel langage/environnement de programmation.

HTH!

13
répondu Avi Flax 2010-05-13 18:26:00

Je ne suis pas sûr du 1 que vous avez comme résultat retourné, mais je suis sûr que cela devrait faire l'affaire:

emit([doc.hits, split[i]], 1);

les règles de tri sont définies dans les docs.

2
répondu Dominykas Blyžė 2010-05-12 13:22:52

basé sur la réponse D'Avi, J'ai créé cette fonction de liste Couchdb qui a fonctionné pour mes besoins, qui est simplement un rapport des événements les plus populaires (clé=nom de l'événement, valeur=participants).

ddoc.lists.eventPopularity = function(req, res) {
  start({ headers : { "Content-type" : "text/plain" } });
  var data = []
  while(row = getRow()) {
    data.push(row);
  }
  data.sort(function(a, b){
    return a.value - b.value;
  }).reverse();
  for(i in data) {
    send(data[i].value + ': ' + data[i].key + "\n");
  }
}

pour référence, voici la fonction de vue correspondante:

ddoc.views.eventPopularity = {
  map : function(doc) {
    if(doc.type == 'user') {
      for(i in doc.events) {
        emit(doc.events[i].event_name, 1);
      }
    }
  },
  reduce : '_count'
}

et la sortie de la fonction list (snipped):

165: Design-Driven Innovation: How Designers Facilitate the Dialog
165: Are Your Customers a Crowd or a Community?
164: Social Media Mythbusters
163: Don't Be Afraid Of Creativity! Anything Can Happen
159: Do Agencies Need to Think Like Software Companies?
158: Customer Experience: Future Trends & Insights
156: The Accidental Writer: Great Web Copy for Everyone
155: Why Everything is Amazing But Nobody is Happy
2
répondu user599515 2011-02-02 05:58:18

c'est une vieille question mais je pense qu'elle mérite quand même une réponse correcte (j'ai passé au moins 20 minutes à chercher la bonne réponse...)

je désapprouve les autres suggestions dans les réponses ici et estime qu'elles sont insatisfaisantes. En particulier, je n'aime pas la suggestion de trier les lignes dans la couche applicative, car il n'a pas une bonne échelle et ne traite pas d'un cas où vous devez limiter le résultat défini dans la base de données.

le une meilleure approche que je suis tombé sur est suggéré dans ce fil de discussion et il pose que si vous avez besoin de trier les valeurs dans la requête vous devriez les ajouter dans le jeu de clés et puis interroger la clé en utilisant une gamme - en spécifiant une clé désirée et en assouplissant la gamme de valeurs. Par exemple, si votre clé est composée du pays, de l'état et de la ville:

emit([doc.address.country,doc.address.state, doc.address.city], doc);

ensuite, vous interrogez juste le pays et obtenir le tri gratuit sur le reste des composants clés:

startkey=["US"]&endkey=["US",{}] 

dans le cas où vous devez également inverser l'ordre - notez que la simple définition de descending: true ne suffira pas. Vous devez en fait Inverser l'ordre des clés de début et de fin, i.e.:

startkey=["US",{}]&endkey=["US"]

voir plus de référence à cette grande source .

2
répondu roy650 2017-05-23 12:10:10

toutes les solutions ci-dessus vont casser les performances de couchdb je pense. Je suis très nouveau dans cette base de données. Comme je le sais, les vues couchdb préparent les résultats avant qu'ils ne soient questionnés. Il semble que nous devions préparer les résultats manuellement. Par exemple, chaque terme de recherche résidera dans la base de données avec des nombres de frappes. Et quand quelqu'un cherche, ses termes de recherche seront recherchés et les augmentations du nombre d'accès. Quand nous voulons voir le terme de recherche popularity, il émettra la paire (hitcount, searchterm).

0
répondu Melug 2013-05-13 23:44:24

le lien Retrieve_the_top_N_tags semble être cassé, mais j'ai trouvé une autre solution ici .

citant le dev qui a écrit Cette solution:

plutôt que de retourner les résultats saisis par la balise dans l'étape de la carte, j'émettrais chaque occurrence de chaque balise à la place. Puis dans l'étape de réduction, Je calculerais les valeurs d'agrégation groupées par étiquette en utilisant un hachage, le transformerait en un tableau, le trierait, et choisissez le top 3.

comme indiqué dans les commentaires, le seul problème serait dans le cas d'une longue queue:

le problème est que vous devez être prudent avec le nombre de tags que vous obtenez; si le résultat est supérieur à 500 octets, couchdb se plaindra de cela, puisque"reduce doit effectivement réduire". 3 ou 6 ou même 20 tags ne devraient pas être un problème, cependant.

ça a parfaitement fonctionné pour moi, cliquez sur le lien pour voir le code !

0
répondu edelans 2013-08-06 16:35:21