2008-08-29 13 views
15

Supposons que j'ai un champ appelé prix pour les documents dans Solr et j'ai ce champ à facettes. Je veux obtenir les facettes comme des plages de valeurs (par exemple: 0-100, 100-500, 500-1000, etc.). Comment faire?Comment obtenir des plages de facettes dans les résultats de solr?

Je peux spécifier les plages au préalable, mais je veux aussi savoir s'il est possible de calculer automatiquement les plages (disons pour 5 valeurs) en fonction des valeurs dans les documents?

Répondre

4

Il se peut bien qu'il y ait une meilleure réponse spécifique à Solr, mais je travaille avec Lucene, et comme vous n'obtenez pas beaucoup d'adhérence, je vais vous prendre. Là, je créerais un Filter avec un FilteredQuery enveloppant l'original Query. Ensuite, j'obtiendrais un FieldCache pour le domaine d'intérêt. Énumérer les hits dans le bitset du filtre, et pour chaque hit, vous obtenez la valeur du champ à partir du cache du champ, et l'ajouter à un SortedSet. Lorsque vous avez tous les hits, divisez la taille de l'ensemble en nombre de plages que vous voulez (cinq à sept est un bon nombre selon les gars de l'interface utilisateur), et plutôt qu'une contrainte à valeur unique, vos facettes seront être une requête de plage avec les limites inférieure et supérieure de chacun de ces sous-ensembles.

Je recommande d'utiliser une logique spéciale pour un petit nombre de valeurs; évidemment, si vous n'avez que quatre valeurs distinctes, cela n'a pas de sens d'essayer d'en faire 5 raffinements. En dessous d'un certain seuil (disons 3 * votre nombre idéal de plages), vous montrez simplement les facettes normalement plutôt que les plages.

14

Pour répondre à votre première question, vous pouvez obtenir des plages de facettes à l'aide du support de requête de facettes générique. un exemple de Here:

http://localhost:8983/solr/select?q=video&rows=0&facet=true&facet.query=price:[*+TO+500]&facet.query=price:[500+TO+*] 

Quant à votre deuxième question (ce qui suggère automatiquement des gammes facettes), ce n'est pas encore mis en œuvre. Certains avancent que ce type d'interrogation serait mieux mis en œuvre sur votre application plutôt que de laisser Solr "deviner" les meilleures gammes de facettes.

Voici quelques discussions sur le sujet:

+1

Peut-être six ans de retard à la fête, mais les liens ne fonctionnent plus. – Bucket

+1

@DesertIvy Par tous les moyens s'il vous plaît les rechercher sur archive.org ou ailleurs et modifier la réponse. –

+0

Wow, je ne savais même pas que ça existait. Excellent outil! – Bucket

6

J'ai travaillé sur la façon de calculer les facettes dynamiques sensibles pour les gammes de prix des produits. La solution implique un pré-traitement des documents et un certain post-traitement des résultats de la requête, mais il ne nécessite qu'une seule requête à Solr, et devrait même fonctionner sur l'ancienne version de Solr comme 1.4.

ronde des prix avant la soumission

En premier lieu, avant de soumettre le document, Rafle le prix de la « belle frontière facette ronde » le plus proche et le stocker dans un champ « rounded_price ». Les utilisateurs aiment leurs facettes pour ressembler à "250-500" et non à "247-483", et arrondir signifie également que vous récupérez des centaines de facettes de prix et non des millions d'entre eux.Avec un peu d'effort le code suivant peut être généralisé à arrondir bien à toute échelle de prix:

public static decimal RoundPrice(decimal price) 
    { 
     if (price < 25) 
      return Math.Ceiling(price); 
     else if (price < 100) 
      return Math.Ceiling(price/5) * 5; 
     else if (price < 250) 
      return Math.Ceiling(price/10) * 10; 
     else if (price < 1000) 
      return Math.Ceiling(price/25) * 25; 
     else if (price < 2500) 
      return Math.Ceiling(price/100) * 100; 
     else if (price < 10000) 
      return Math.Ceiling(price/250) * 250; 
     else if (price < 25000) 
      return Math.Ceiling(price/1000) * 1000; 
     else if (price < 100000) 
      return Math.Ceiling(price/2500) * 2500; 
     else 
      return Math.Ceiling(price/5000) * 5000; 
    } 

prix admissibles vont 1,2,3, ..., 24,25,30,35, ..., 95100110 , ..., 240, 250, 275, 300, 325, ..., 975, 100 et ainsi de suite.

Obtenez toutes les facettes sur les prix arrondis

de deuxième, lors de la présentation de la requête, demander toutes les facettes sur les prix arrondis triées par prix: facet.field=rounded_price. Grâce à l'arrondi, vous aurez au plus quelques centaines de facettes en arrière.

Combine facettes adjacentes en facettes plus grandes

Troisièmement, une fois que vous avez les résultats, l'utilisateur veut voir seulement 3 à 7 facettes, non pas des centaines de facettes. Donc, combinez les facettes adjacentes en quelques grandes facettes (appelées "segments") en essayant d'obtenir un nombre à peu près égal de documents dans chaque segment. Le code suivant, plus compliqué, fait ceci, retournant des tuples de (début, fin, compte) appropriés pour effectuer des requêtes de plage. Les chiffres retournés seront prix corrects fournis ont été arrondis jusqu'à à la limite la plus proche:

public static List<Tuple<string, string, int>> CombinePriceFacets(int nSegments, ICollection<KeyValuePair<string, int>> prices) 
    { 
     var ranges = new List<Tuple<string, string, int>>(); 
     int productCount = prices.Sum(p => p.Value); 
     int productsRemaining = productCount; 
     if (nSegments < 2) 
      return ranges; 
     int segmentSize = productCount/nSegments; 
     string start = "*"; 
     string end = "0"; 
     int count = 0; 
     int totalCount = 0; 
     int segmentIdx = 1; 
     foreach (KeyValuePair<string, int> price in prices) 
     { 
      end = price.Key; 
      count += price.Value; 
      totalCount += price.Value; 
      productsRemaining -= price.Value; 
      if (totalCount >= segmentSize * segmentIdx) 
      { 
       ranges.Add(new Tuple<string, string, int>(start, end, count)); 
       start = end; 
       count = 0; 
       segmentIdx += 1; 
      } 
      if (segmentIdx == nSegments) 
      { 
       ranges.Add(new Tuple<string, string, int>(start, "*", count + productsRemaining)); 
       break; 
      } 
     } 
     return ranges; 
    } 

Filtrer les résultats par sélectionnés facette

Quatrièmement, supposons que (« 250 », « 500 », 38) était l'un des segments résultants. Si l'utilisateur sélectionne "$ 250 à $ 500" comme filtre, il suffit de faire une requête de filtre fq=price:[250 TO 500]