Мы находимся на Sitecore 6.4 и используем модуль расширенного поиска с общим источником и наблюдаем большое снижение производительности поиска по сайту, когда процесс повторного индексирования Sitecore запускается и обновляет изменения в веб-базе данных.
Когда мы начинаем полную публикацию сайта, менеджер индексирования подхватывает изменения и обрабатывает записи истории, которые, в свою очередь, переиндексируют каждый элемент, который был затронут. Поскольку это происходит для каждого элемента, вы можете видеть, как изменяется индекс Lucene на диске при просмотре каталога (количество файлов растет и изменяется по мере того, как вы наблюдаете за этим).
Если вы попробуете выполнить поиск на публичном сайте, когда это происходит, поиск может занять заметно больше времени, а при большой нагрузке может потребоваться до 15 секунд до завершения процесса переиндексации.
Я вижу, что этот процесс контролируется классом IndexingProvider. Есть ли способ переопределить этот класс и реализовать свой собственный?
Мы рассмотрели логику поиска и увидели, что при каждом запросе поиска создается объект IndexSearchContext, который в свою очередь создает новый IndexSearcher. Мы изменили часть логики таким образом, чтобы IndexSearchContext сохранялся как синглтон, что, конечно, означает, что несколько запросов могут обслуживаться одним и тем же Lucene IndexSearcher. Это резко сократило потребление памяти, поскольку для повышения производительности рекомендуется использовать один и тот же поисковик.
Однако при этом изменения в индексе не будут подхвачены до тех пор, пока не будет создан новый IndexSearcher. Нам нужен способ уведомить наш код о том, что процесс индексирования завершен, и тогда мы сможем сбросить наш объект singleton IndexSearchContext. Как мы можем интегрировать эту логику в код конфигурации Sitecore?
При восстановлении индекса вручную на это уходит всего около 5 секунд. Очевидно, что это эффективно удаляет индекс, а затем создает его заново, но почему обновление по элементам занимает так много времени? Нет ли лучшего способа обновления, не переходя от элемента к элементу и не влияя на публичный сайт?
Я ожидал, что эта проблема затронет и других, поэтому мне хотелось бы услышать, как люди решили эту проблему.
EDIT - дополнительная информация с форума Sitecore
Код Sitecore.Search, похоже, активно использует создание/размещение новых объектов Lucene для одной операции. Он не кажется слишком масштабируемым для больших сред, вот почему я был удивлен, когда увидел этот код. Особенно если индексы большие и каждый день происходит много обновлений/публикаций контента.
Глядя на классы через dotPeek, я не вижу, как мы можем переопределить IndexUpdateContext, поскольку он создается в не виртуальном методе. Пользовательский DatabaseCrawler может получить некоторый доступ, но только к уже созданному объекту контекста.
Я заметил, что мы можем определить нашу собственную реализацию индекса в web.config для каждого индекса. Мы также можем повторно реализовать краулер (у нас уже есть продвинутый краулер из общего модуля) и, возможно, получить некоторый контроль над процессом индексирования. Я бы не хотел вытаскивать слишком много кода Sitecore в нашу собственную реализацию, так как это может повлиять на будущие обновления.
Однако у меня есть один вопрос относительно IndexingProvider. В следующем методе:
private void UpdateItem(HistoryEntry entry, Database database)
{
int count = database.Indexes.Count;
if (count != 0 || this.OnUpdateItem != null)
{
Item obj = database.GetItem(entry.ItemId, entry.ItemLanguage, entry.ItemVersion);
if (obj != null)
{
if (this.OnUpdateItem != null)
this.OnUpdateItem((object) this, (EventArgs) new SitecoreEventArgs("index:updateitem", new object[2]
{
(object) database,
(object) obj
}, new EventResult()));
for (int index = 0; index < count; ++index)
database.Indexes[index].UpdateItem(obj);
}
}
}
Он запускает событие обновления, которое обрабатывается DatabaseCrawler, поскольку он присоединен к событию IndexingProvider.OnUpdateItem; но почему метод выше также вызывает метод Sitecore.Data.Indexing.Index.UpdateItem? Я думал, что это пространство имен было упразднено в версии 6.5, поэтому я удивлен, увидев связь между новым и старым пространством имен.
Итак, похоже, что DatabaseCrawler обрабатывает обновление, которое удаляет элемент, а затем снова добавляет его в индекс; а затем старый Sitecore.Data.Indexing.Index также пытается обновить его. Наверняка здесь что-то не так? Я не знаю, поэтому, пожалуйста, поправьте меня, если я ошибаюсь, вот как это выглядит, когда я просматриваю декомпилированный код без отладки.