2012-04-20 2 views
6

Ich überlege RavenDb, ein 'erweiterte facettierte Suche' Szenario zu implementieren.
Ich muss mich mit einer komplexen hierarchischen Taxonomie und gemeinsamen Facetten über die verschiedenen Zweige der Baumstruktur befassen, während ich die Volltextsuche und alle anderen grundlegenden Funktionen unterstütze.Hierarchische Taxonomie in der Facettensuche mit RavenDb/Lucene?

Gibt es irgendwelche Ressourcen, die dokumentieren, wie man das mit der RavenDb API macht?

Insanely komplexes Papier zu dem Thema: Beyond Basic Faceted Search
Solr Weg: HierarchicalFaceting

Antwort

5

..

using System.Collections.Generic; 
using System.Linq; 
using NUnit.Framework; 
using Raven.Abstractions.Data; 
using Raven.Client; 
using Raven.Client.Document; 
using Raven.Client.Indexes; 
using Raven.Client.Linq; 

namespace Prototype.Search.Tests 
{ 
    [TestFixture] 
    public class HierarchicalFaceting 
    { 
     // 
     // Document definition 
     // 
     public class Doc 
     { 
      public Doc() 
      { 
       Categories = new List<string>(); 
      } 

      public int Id { get; set; } 
      public List<string> Categories { get; set; } 
     } 

     // 
     // Data sample 
     // 
     public IEnumerable<Doc> GetDocs() 
     { 
      yield return new Doc { Id = 1, Categories = new List<string> { "0/NonFic", "1/NonFic/Law"} }; 
      yield return new Doc { Id = 2, Categories = new List<string> { "0/NonFic", "1/NonFic/Sci" } }; 
      yield return new Doc { Id = 3, Categories = new List<string> { "0/NonFic", "1/NonFic/Hist", "1/NonFic/Sci", "2/NonFic/Sci/Phys" } }; 
     } 

     // 
     // The index 
     // 
     public class DocByCategory : AbstractIndexCreationTask<Doc, DocByCategory.ReduceResult> 
     { 
      public class ReduceResult 
      { 
       public string Category { get; set; } 
      } 

      public DocByCategory() 
      { 
       Map = docs => 
         from d in docs 
         from c in d.Categories 
         select new 
           { 
            Category = c 
           }; 
      } 
     } 

     // 
     // FacetSetup 
     // 
     public FacetSetup GetDocFacetSetup() 
     { 
      return new FacetSetup 
         { 
          Id = "facets/Doc", 
          Facets = new List<Facet> 
             { 
              new Facet 
               { 
                Name = "Category" 
               } 
             } 
         }; 
     } 

     [SetUp] 
     public void SetupDb() 
     { 
      IDocumentStore store = new DocumentStore() 
      { 
       Url = "http://localhost:8080" 
      }; 
      store.Initialize(); 
      IndexCreation.CreateIndexes(typeof(HierarchicalFaceting).Assembly, store); 

      var session = store.OpenSession(); 
      session.Store(GetDocFacetSetup()); 
      session.SaveChanges(); 

      store.Dispose(); 
     } 

     [Test] 
     [Ignore] 
     public void DeleteAll() 
     { 
      IDocumentStore store = new DocumentStore() 
      { 
       Url = "http://localhost:8080" 
      }; 
      store.Initialize(); 

      store.DatabaseCommands.DeleteIndex("Raven/DocByCategory"); 
      store.DatabaseCommands.DeleteByIndex("Raven/DocumentsByEntityName", new IndexQuery()); 

      store.Dispose(); 
     } 

     [Test] 
     [Ignore] 
     public void StoreDocs() 
     { 
      IDocumentStore store = new DocumentStore() 
      { 
       Url = "http://localhost:8080" 
      }; 
      store.Initialize(); 

      var session = store.OpenSession(); 

      foreach (var doc in GetDocs()) 
      { 
       session.Store(doc); 
      } 

      session.SaveChanges(); 
      session.Dispose(); 
      store.Dispose(); 
     } 

     [Test] 
     public void QueryDocsByCategory() 
     { 
      IDocumentStore store = new DocumentStore() 
      { 
       Url = "http://localhost:8080" 
      }; 
      store.Initialize(); 

      var session = store.OpenSession(); 

      var q = session.Query<DocByCategory.ReduceResult, DocByCategory>() 
       .Where(d => d.Category == "1/NonFic/Sci") 
       .As<Doc>(); 

      var results = q.ToList(); 
      var facetResults = q.ToFacets("facets/Doc").ToList(); 

      session.Dispose(); 
      store.Dispose(); 
     } 

     [Test] 
     public void GetFacets() 
     { 
      IDocumentStore store = new DocumentStore() 
      { 
       Url = "http://localhost:8080" 
      }; 
      store.Initialize(); 

      var session = store.OpenSession(); 

      var q = session.Query<DocByCategory.ReduceResult, DocByCategory>() 
       .Where(d => d.Category.StartsWith("1/NonFic")) 
       .As<Doc>(); 

      var results = q.ToList(); 
      var facetResults = q.ToFacets("facets/Doc").ToList(); 

      session.Dispose(); 
      store.Dispose(); 
     } 
    } 
} 
+0

danke für den Code, funktioniert wie ein Kinderspiel! Was ist der beste Ansatz, wenn Doc auch ein Titelfeld hat, und ich möchte die Facetten basierend auf der Tatsache filtern, dass dieser Titel eine bestimmte Zeichenfolge enthält? –

1

Ich würde den Baum-Suche Teil dieses unter Verwendung von reinen Lucene Griff für Geschwindigkeit willen. 2 Ansätze sind die Eltern-Kind-Verknüpfungen Methode und die Pfadaufzählung/"Dewey Decimal" -Methode.

Eltern-Kind ist, wie wir alle gelernt haben, verkettete Listen wieder in der Algorithmusklasse zu implementieren. Es ist einfach zu aktualisieren, aber Abfragen erfordern den Besuch jedes Knotens (Sie können beispielsweise nicht direkt von einem Elternteil zu seinem Urenkel gelangen). Vorausgesetzt, dass Sie alle Vorfahren eines Knotens trotzdem besuchen müssen, um alle Attribute zu erhalten (da die Idee darin besteht, die Attribute zu teilen), kann es ein strittiger Punkt sein, alle Vorfahren zu besuchen.

How to store tree data in a Lucene/Solr/Elasticsearch index or a NoSQL db? umfasst die Pfadaufzählung/"Dewey Decimal" -Methode.

Jeder Ansatz kann eine beliebig komplexe Hierarchie handhaben, solange es sich um eine echte Hierarchie handelt (d. H. Ein gerichtetes azyklisches Diagramm (D.A.G.)). Schließlich

+1

Zunächst vielen Dank für Ihre Zeit. Ich muss jedoch eine Sache klarstellen .. meine Daten - in Esent gespeichert - ist nicht hierarchisch; Die verschiedenen Facetten meiner Daten sind hierarchisch. In der Sprache Lucene glaube ich, dass sie als _terms_ bezeichnet werden. Die Begriffe selbst sind also hierarchisch. Beziehen Sie sich auf das Papier, das ich oben auf Seite 36 verlinkt habe, und sehen Sie sich das Diagramm in der oberen rechten Ecke an. Mit Ihrem Ansatz würde ich einen Index in Lucene entwerfen, um hierarchische Daten abzufragen, aber ich suche nach sauberen und einfachen Ressourcen, um dieses Konzept auf Lucenes Begriffe anzuwenden: eine hierarchische Taxonomie. – maxbeaudoin

1

ich es behoben bereits.

erstelle ich den Index wie folgt:

public class ProductByCategory : AbstractIndexCreationTask<Product, ProductByCategory.ReduceResult> 
{ 
    public class ReduceResult 
    { 
     public string Category { get; set; } 
     public string Title { get; set; } 
    } 

    public ProductByCategory() 
    { 
     Map = products => 
       from p in products 
       from c in p.Categories 
       select new 
       { 
        Category = c, 
        Title = p.Title 
       }; 
     Stores.Add(x => x.Title, FieldStorage.Yes); 
     Indexes.Add(x => x.Title, FieldIndexing.Analyzed); 
    } 
} 

Und ich abfragen, es mag:

var q = session.Query<ProductByCategory.ReduceResult, ProductByCategory>().Search(x => x.Title, "Sony") 
.Where(r => r.Category.StartsWith("1/beeld en geluid")).As<Product>(); 

var facetResults = q.ToFacets("facets/ProductCategory");