RavenDb で「高度なファセット検索」シナリオを実装することを検討しています。
全文検索やその他すべての基本機能をサポートしながら、ツリーのさまざまなブランチにまたがる複雑な階層分類法と共有ファセットに対処する必要があります。
RavenDb API を使用してこれを行う方法を文書化したリソースはありますか?
この主題に関する非常に複雑な論文: Beyond Basic Faceted Search
Solr の方法: HierarchicalFaceting
RavenDb で「高度なファセット検索」シナリオを実装することを検討しています。
全文検索やその他すべての基本機能をサポートしながら、ツリーのさまざまなブランチにまたがる複雑な階層分類法と共有ファセットに対処する必要があります。
RavenDb API を使用してこれを行う方法を文書化したリソースはありますか?
この主題に関する非常に複雑な論文: Beyond Basic Faceted Search
Solr の方法: HierarchicalFaceting
ついに..
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();
}
}
}
私はすでにそれを修正しました。
次のようにインデックスを作成します。
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);
}
}
そして、次のようにクエリします。
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");
速度を上げるために、純粋な Lucene を使用して、このツリー検索部分を処理します。2つのアプローチは、親子リンケージ法とパス列挙/「Dewey Decimal」法です。
親子は、リンクされたリストをアルゴリズムクラスに実装することを学んだ方法です。更新は簡単ですが、クエリでは各ノードにアクセスする必要があります (たとえば、親からそのひ孫に直接アクセスすることはできません)。とにかくすべての属性を取得するためにノードのすべての祖先を訪問する必要があることを考えると (アイデアは属性を共有することであるため)、すべての祖先を訪問しなければならないことは議論の余地があるかもしれません。
ツリー データを Lucene/Solr/Elasticsearch インデックスまたは NoSQL データベースに保存する方法は? path-enumeration/'Dewey Decimal' メソッドをカバーしています。
どちらのアプローチも、それが真の階層 (有向非巡回グラフ (DAG)) である限り、任意の複雑な階層を処理できます。