RavenDB - 使用多个术语查询集合

时间:2013-05-07 14:10:48

标签: c# nosql ravendb

我希望能够收回所有包含我指定的所有标签的博文。

public class Post
{
    public int Name { get; set; }
    public List<string> Tags { get; set; }
}

我想带回'c#'和'html'标签的所有帖子。

这个问题与我的问题相同,但我无法让我的榜样有效。 Linq query with multiple Contains/Any for RavenDB

我想知道为什么当标签中有一个带有'c#'和'html'的帖子时,下面的例子没有带回任何结果。

如果有人能够解释现在是否有一种新的,更优雅的方法来解决这个问题,理想情况下使用强类型查询语法,那将是很棒的,即

var query = s.Query<Entity, IndexClass>()

-

using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Raven.Abstractions.Indexing;
using Raven.Client.Embedded;
using Raven.Client.Indexes;

namespace RavenDB
{
    public class Blog
    {
        public string Name { get; set; }
        public List<string> Tags { get; set; }
    }

    public class BlogsByTags : AbstractIndexCreationTask<Blog>
    {
        public BlogsByTags()
        {
            Map = docs => from doc in docs
                          select new
                              {
                                  Tags = doc.Tags
                              };

            Index(x => x.Tags, FieldIndexing.Analyzed);
        }
    }

    [TestFixture]
    public class Runner : UsingEmbeddedRavenStore
    {
        [Test]
        public void Run()
        {
            Open();
            IndexCreation.CreateIndexes(typeof(BlogsByTags).Assembly, Store);

            var blogs = new List<Blog>
                {
                    new Blog{Name = "MVC", Tags = new List<string>{"html","c#"}},
                    new Blog{Name = "HTML5", Tags = new List<string>{"html"}},
                    new Blog{Name = "Version Control", Tags = new List<string>{"git"}},
                };

            using (var session = Store.OpenSession())
            {             
                foreach (var blog in blogs)
                {
                    session.Store(blog);
                }
                session.SaveChanges();
            }

            var tags = new List<string> { "c#", "html" };

            List<Blog> blogQueryResults;

            using (var s = Store.OpenSession())
            {

                blogQueryResults = s.Advanced.LuceneQuery<Blog, BlogsByTags>()
                  .Where(string.Format("Tags:({0})", string.Join(" AND ", tags))).ToList();                
            }

            Assert.AreEqual(1, blogQueryResults.Count());
        }
    }

    public abstract class UsingEmbeddedRavenStore
    {
        protected EmbeddableDocumentStore Store { get; set; }

        protected void Open()
        {
            Store = new EmbeddableDocumentStore
            {
                RunInMemory =
                    true
            };

            Store.Initialize();
        }

        protected void Dispose()
        {
            Store.Dispose();
        }
    }
}

1 个答案:

答案 0 :(得分:4)

唯一的问题是,由于您处于单元测试中,因此需要明确允许在写入数据和检查索引之间的时间。否则,您的索引是陈旧的。请参阅these docs

s.Advanced.LuceneQuery<Blog, BlogsByTags>()

 // Unit tests should wait explicitly.
 // Don't do this outside of a unit test.
 .WaitForNonStaleResults()

 .Where(string.Format("Tags:({0})", string.Join(" AND ", tags)))

您还询问了如何在不使用高级lucene语法的情况下执行相同的查询。您可以使用.Search扩展方法,因此:

s.Query<Blog, BlogsByTags>()
 .Customize(x => x.WaitForNonStaleResults())
 .Search(x => x.Tags, string.Join(" AND ", tags))

还有一件事你应该改变。在进行单元测试时,您确实不希望单元测试扫描程序集中的索引。它可能会为其他测试选择索引。

// Instead of scanning like this
IndexCreation.CreateIndexes(typeof(BlogsByTags).Assembly, store);

// Create the single index like this
store.ExecuteIndex(new BlogsByTags());

最后,我想指出RavenDB.Tests.Helpers nuget包,您可以使用它来简化测试。它为您完成了很多设置工作。它使用XUnit - 所以如果你与NUnit绑定,那么你可能想要按照自己的方式做事。