Ожидаемая производительность RavenDb для запроса документов, количество которых исчисляется миллионами - PullRequest
4 голосов
/ 23 марта 2012

Мне удалось загрузить пару миллионов документов с помощью встроенной версии RavenDb, довольно приятно!

Теперь я пытаюсь запросить эти элементы и обнаруживаю, что производительность не та, которую я ожидал, почти мгновенная, если это возможно, а вместо этого более 18 секунд на довольно громоздкой машине.

Ниже вы найдете мой наивный код.

Примечание. Теперь я решил эту проблему, и окончательный код находится внизу поста.Вывод заключается в том, что вам нужны индексы, они должны быть правильного типа, и RavenDB должен быть осведомлен о них.ОЧЕНЬ доволен производительностью и качеством возвращаемых записей через механизм запросов.

Спасибо, Стивен

using (var store = new EmbeddableDocumentStore { DataDirectory = @"C:\temp\ravendata" }.Initialize())
{
    using (IDocumentSession session = store.OpenSession())
    {
        var q = session.Query<Product>().Where(x => x.INFO2.StartsWith("SYS")).ToList();
    }
}


[Serializable]
public class Product
{
    public decimal ProductId { get; set; }
    ....
    public string INFO2 { get; set; }
}

РЕДАКТИРОВАТЬ

Я добавил этот класс

public class InfoIndex_Search : AbstractIndexCreationTask<Product>
{
    public InfoIndex_Search()
    {
        Map = products => 
            from p in products
                          select new { Info2Index = p.INFO2 };

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

и изменил вызывающий метод, чтобы он выглядел следующим образом.

        using (var store = new EmbeddableDocumentStore { DataDirectory = @"C:\temp\ravendata" }.Initialize())
        {
            // Tell Raven to create our indexes.
            IndexCreation.CreateIndexes(Assembly.GetExecutingAssembly(), store);

            List<Product> q = null;
            using (IDocumentSession session = store.OpenSession())
            {
                q = session.Query<Product>().Where(x => x.INFO2.StartsWith("SYS")).ToList();
                watch.Stop();
            }
        }

Но я все еще сообщаю 18 секунд, чтобы выполнить поиск.Что мне не хватает?С другой стороны, в папке C: \ temp \ ravendata \ Indexes \ InfoIndex% 2fSearch появилось довольно много новых файлов, хотя их было не так много, как при вставке данных, но после запуска этого кода они, похоже, исчезли.несколько раз пытаясь запросить.Если IndexCreation.CreateIndexes (Assembly.GetExecutingAssembly (), store);быть вызванным до вставки, и только потом?

EDIT1

Используя этот код, я смог получить запрос почти в одном экземпляре, но, кажется, вы можете выполнить его только один раз,так что напрашивается вопрос.Где это выполняется и каковы надлежащие процедуры инициализации?

store.DatabaseCommands.PutIndex("ProdcustByInfo2", new IndexDefinitionBuilder<Product>
{
    Map = products => from product in products
                      select new { product.INFO2 },
    Indexes =
            {
                { x => x.INFO2, FieldIndexing.Analyzed}
            }
});

EDIT2: рабочий пример

static void Main()
{
    Stopwatch watch = Stopwatch.StartNew();

    int q = 0;
    using (var store = new EmbeddableDocumentStore { DataDirectory = @"C:\temp\ravendata" }.Initialize())
    {
        if (store.DatabaseCommands.GetIndex("ProdcustByInfo2") == null)
        {
            store.DatabaseCommands.PutIndex("ProdcustByInfo2", new IndexDefinitionBuilder<Product>
            {
                Map = products => from product in products
                                  select new { product.INFO2 },
                Indexes = { { x => x.INFO2, FieldIndexing.Analyzed } }
            });
        }
        watch.Stop();
        Console.WriteLine("Time elapsed to create index {0}{1}", watch.ElapsedMilliseconds, System.Environment.NewLine);

        watch = Stopwatch.StartNew();               
        using (IDocumentSession session = store.OpenSession())
        {
            q = session.Query<Product>().Count();
        }
        watch.Stop();
        Console.WriteLine("Time elapsed to query for products values {0}{1}", watch.ElapsedMilliseconds, System.Environment.NewLine);
        Console.WriteLine("Total number of products loaded: {0}{1}", q, System.Environment.NewLine);

        if (q == 0)
        {
            watch = Stopwatch.StartNew();
            var productsList = Parsers.GetProducts().ToList();
            watch.Stop();
            Console.WriteLine("Time elapsed to parse: {0}{1}", watch.ElapsedMilliseconds, System.Environment.NewLine);
            Console.WriteLine("Total number of items parsed: {0}{1}", productsList.Count, System.Environment.NewLine);

            watch = Stopwatch.StartNew();
            productsList.RemoveAll(_ => _ == null);
            watch.Stop();
            Console.WriteLine("Time elapsed to remove null values {0}{1}", watch.ElapsedMilliseconds, System.Environment.NewLine);
            Console.WriteLine("Total number of items loaded: {0}{1}", productsList.Count, System.Environment.NewLine);

            watch = Stopwatch.StartNew();
            int batch = 0;
            var session = store.OpenSession();
            foreach (var product in productsList)
            {
                batch++;
                session.Store(product);
                if (batch % 128 == 0)
                {
                    session.SaveChanges();
                    session.Dispose();
                    session = store.OpenSession();
                }
            }
            session.SaveChanges();
            session.Dispose();
            watch.Stop();
            Console.WriteLine("Time elapsed to populate db from collection {0}{1}", watch.ElapsedMilliseconds, System.Environment.NewLine);
        }

        watch = Stopwatch.StartNew();
        using (IDocumentSession session = store.OpenSession())
        {
            q = session.Query<Product>().Where(x => x.INFO2.StartsWith("SYS")).Count();
        }
        watch.Stop();
        Console.WriteLine("Time elapsed to query for term {0}{1}", watch.ElapsedMilliseconds, System.Environment.NewLine);
        Console.WriteLine("Total number of items found: {0}{1}", q, System.Environment.NewLine);
    }
    Console.ReadLine();
}

Ответы [ 2 ]

6 голосов
/ 23 марта 2012

Во-первых, есть ли у вас индекс, охватывающий INFO2?

Во-вторых, см. Блог Даниэля Ланга "Поиск по свойствам строк в RavenDB" здесь:

http://daniellang.net/searching-on-string-properties-in-ravendb/

Если это поможет, вот как я создал индекс:

public class LogMessageCreatedTime : AbstractIndexCreationTask<LogMessage>
{
    public LogMessageCreatedTime()
    {
        Map = messages => from message in messages
                          select new { MessageCreatedTime = message.MessageCreatedTime };
    }
}

И как я добавил его во время выполнения:

private static DocumentStore GetDatabase()
{            
    DocumentStore documentStore = new DocumentStore();            

    try
    {
        documentStore.ConnectionStringName = "RavenDb";                
        documentStore.Initialize();

        // Tell Raven to create our indexes.
        IndexCreation.CreateIndexes(typeof(DataAccessFactory).Assembly, documentStore);
    }
    catch
    {
        documentStore.Dispose();
        throw;
    }

    return documentStore;
}

В моем случае мне не нужно было запрашиватьиндексировать явно;он просто использовался, когда я обычно спрашивал.

0 голосов
/ 23 марта 2012

Как подсказывает Боб, вы должны убедиться, что в Raven созданы индексы, которые охватывают поля, которые вы собираетесь запрашивать.

Ворон довольно быстр и может отпустить вас без особых усилий. Однако, как только вы начнете получать номера документов большого размера или вам понадобится что-то нестандартное, вы обнаружите, что вам нужны статические индексы.

Существует множество примеров по настройке и использованию индексов в Raven.

...