RavenDb通过对文档的嵌套值应用谓词来进行分面搜索

时间:2011-10-27 08:01:14

标签: mapreduce ravendb faceted-search

在RavenDB中,我了解当您需要计算符合特定条件的属性时,可以实现

  1. 通过针对您要分组的属性名称创建构面,
  2. 然后在上述属性和where子句中所需的属性上创建索引。
  3. 最后使用上面的索引发出查询。并使用ToFacets扩展程序实现查询。
  4. 但是当你的where子句碰巧包含对作为文档上的值集合的属性的谓词时会发生什么?因为如果我将集合中的嵌套属性添加到父文档的索引中,那么我在faced上的属性计数将不准确?

    例如

    public class Camera { 
      string Make { get;set; }
      string Model { get;set; } 
      double Price { get;set; }
      IEnumerable<string> Showrooms { get;set; }
    }
    

    我的查询看起来像是

    (from camera in session.Query<Camera, Camera_Facets>() 
     where camera.Price < 100 && camera.ShowRooms.Any(s => s.In("VIC", "ACT", "QLD")) 
     select new { 
           camera.Make, 
           camera.Model, 
           camera.Price}
     ).ToFacets("facets/CameraFacets");
    

    更新: 这是失败的测试

    [TestFixture]
    public class FacetedSearchWhenQueryingNestedCollections
    {
        public class Car
        {
            public Car()
            {
                Locations = new List<string>();
            }
    
            public string Id { get; set; }
            public string Make { get; set; }
            public string Model { get; set; }
            public double Price { get; set; }
            public IEnumerable<string> Locations { get; set; }
        }
    
        public class Car_Facets : AbstractIndexCreationTask<Car>
        {
            public Car_Facets()
            {
                Map = cars => from car in cars
                              select new {car.Make, car.Model, car.Price};
            }
        }
    
        private static IDocumentSession OpenSession
        {
            get { return new EmbeddableDocumentStore {RunInMemory = true}.Initialize().OpenSession(); }
        }
    
        [Test]
        public void CanGetFacetsWhenQueryingNesetedCollectionValues()
        {
            var cars = Builder<Car>.CreateListOfSize(50)
                .Section(0, 10)
                    .With(x => x.Model = "Camry")
                    .With(x => x.Make = "Toyota")
                    .With(x => x.Price = 2000)
                    .With(x => x.Locations = new[] {"VIC", "ACT"})
                .Section(11, 20)
                    .With(x => x.Model = "Corolla")
                    .With(x => x.Make = "Toyota")
                    .With(x => x.Price = 1000)
                    .With(x => x.Locations = new[] { "NSW", "ACT" })
                .Section(21, 30)
                    .With(x => x.Model = "Rx8")
                    .With(x => x.Make = "Mazda")
                    .With(x => x.Price = 5000)
                    .With(x => x.Locations = new[] { "ACT", "SA", "TAS" })
                .Section(31, 49)
                    .With(x => x.Model = "Civic")
                    .With(x => x.Make = "Honda")
                    .With(x => x.Price = 1500)
                    .With(x => x.Locations = new[] { "QLD", "SA", "TAS" })
                .Build();
    
            IDictionary<string, IEnumerable<FacetValue>> facets;
    
            using(var s = OpenSession)
            {
                s.Store(new FacetSetup { Id = "facets/CarFacets", Facets = new List<Facet> { new Facet { Name = "Model" }, new Facet { Name = "Make" }, new Facet { Name = "Price" } } });
                s.SaveChanges();
    
                IndexCreation.CreateIndexes(typeof(Car_Facets).Assembly, s.Advanced.DocumentStore);
    
                foreach (var car in cars)
                    s.Store(car);
    
                s.SaveChanges();
    
                s.Query<Car, Car_Facets>().Customize(x => x.WaitForNonStaleResults()).ToList();
    
                facets = s.Query<Car, Car_Facets>()
                    .Where(x => x.Price < 3000)
                    .Where(x => x.Locations.Any(l => l.In("QLD", "VIC")))
                    .ToFacets("facets/CarFacets");
            }
    
            Assert.IsNotNull(facets);
            Assert.IsTrue(facets.All(f => f.Value.Count() > 0));
            Assert.IsTrue(facets.All(f => f.Value.All(x => x.Count > 0)));
        }
    
        [TearDown]
        public void ClearData()
        {
            using(var s = OpenSession)
            {
                foreach (var car in s.Query<Car>().ToList())
                    s.Delete(car);
    
                s.SaveChanges();
            }
        }
    }
    

    但是如果我改变我的查询。 (不再查询嵌套集合)

        facets = s.Query<Car, Car_Facets>()
                    .Where(x => x.Price < 3000)
                    .ToFacets("facets/CarFacets");
    

    现在我在字典中得到3个Enumerations,都带有值。

1 个答案:

答案 0 :(得分:2)

如果我将索引更改为

    public class Car_Facets : AbstractIndexCreationTask<Car>
    {
        public Car_Facets()
        {
            Map = cars => from car in cars
                          from location in car.Locations
                          select new {car.Make, car.Model, car.Price, Location = location};
        }
    }

为投影创建一个类

    public class CarOnLocation
    {
        public string Make { get; set; }
        public string Model { get; set; }
        public double Price { get; set; }
        public string Location { get; set; }
    }

然后查询为

    facets = s.Query<Car, Car_Facets>().AsProjection<CarOnLocation>()
                .Where(x => x.Price < 3000)
                .Where(x => x.Location.In("QLD", "VIC"))
                .ToFacets("facets/CarFacets");

它有效。