Поиск Grails Lucene занимает много времени
Для фона я использую Grails v2.2.1 и плагин Searchable (v0.6.4) для моего приложения, хотя я новичок в настройке Lucene.
Журналы показывают, что поиск занимает 26 миллионов секунд, но транзакция компаса занимает около 15 секунд, чтобы вернуться:
2013-04-23 00:40:34,269 DEBUG grails.plugin.searchable.internal.
compass.search.DefaultSearchMethod - query: [+kind:band +name:snoop], [4] hits, took [26] millis
2013-04-23 00:40:49,965 DEBUG org.compass.core.transaction.LocalTransaction - Committing local transaction on thread [http-bio-8080-exec-10] Compass [1176020804] Session [2089649487]
Похоже, что это больше проблема с Compass, чем с Lucene, так как запрос выполняется быстро, но отображение Compass привязывает мой Java-процесс к почти 100% CPU и зависает слишком долго.
У меня проиндексировано около 3500 доменных объектов, и моя модель домена выглядит следующим образом: я пытался индексировать только имена полей и идентификаторы, но, похоже, он отображает все в домене при просмотре через Люка.
package com.bandbot
class Band {
def slugGeneratorService
static searchable = {
mapping {
spellCheck "exclude"
only: ['name', 'id']
}
}
String name
String biography
String profileImage
String slug
String similarBands // this will store bands/url/pic in the form of Kanye West::url::img.png~Queen::url::img.png
boolean onTour // is this band currently touring? (Info from lastfm)
String mbid // This band's MusicBrainz ID see @ http://musicbrainz.org/doc/MusicBrainz_Identifier
String bandUrl
String lastFMUrl // stores the lastfm url
Date dateOfInception
Date dateDisbanded
Date lastUpdated
static belongsTo = [Genre, BandbotUser]
static hasMany = [ events : Event, genres : Genre ]
def beforeInsert() {
lastUpdated = new Date()
this.slug = slugGeneratorService.generateSlug(this.class, "slug", name)
}
def beforeUpdate() {
lastUpdated = new Date()
if (isDirty('name')) {
this.slug = slugGeneratorService.generateSlug(this.class, "slug", name)
}
}
static constraints = {
name(nullable: false, blank: false, unique: true)
slug(nullable: true)
bandUrl(nullable: true)
dateDisbanded(nullable: true)
mbid(nullable: true)
dateOfInception(nullable: true)
biography(nullable: true)
similarBands(nullable: true)
lastUpdated(nullable: true)
lastFMUrl(nullable: true)
kind( display: false )
}
static mapping = {
onTour defaultValue: false
biography type: 'text'
similarBands type: 'text'
}
String toString(){name}
}
Моя логика поиска в контроллере для групп:
def search() {
if (!params.q?.trim()) {
return [:]
}
try {
def searchResult
if (params.sort) {
searchResult = searchableService.search(
params.q.trim(),
[offset: params.offset ? params.int('offset') : 0,
max: params.max ? params.int('max') : 10,
sort: params.sort, order: params.order? params.order : 'asc']
)
}
else {
searchResult = searchableService.search(
params.q.trim(),
[offset: params.offset ? params.int('offset') : 0,
max: params.max ? params.int('max') : 10]
)
}
return [searchResult: searchResult, params: params]
} catch (SearchEngineQueryParseException ex) {
return [parseException: true, params: params]
}
}
Любые идеи очень приветствуются. Это мой самообучающийся проект, и я действительно хочу найти правильный путь.:) Спасибо, Кевин
1 ответ
У меня возникла та же проблема с использованием плагина для поиска в недавнем приложении Grails, которое я разрабатывал. У меня было два предметных объекта с отношением один ко многим, которые я индексировал для поиска. Для простоты я просто показываю объекты Домена с их полями и связями. Я не показываю какую-либо карту или информацию об ограничениях. Вот мои оригинальные занятия
class CodeValue{
static searchable ={
only:['value', 'description']
value boost: 2.0
}
String value
String description
static belongsTo = [codeset: CodeSet]
}
class CodeSet{
static searchable ={
only:['name', 'description']
name boost: 2.0
}
String name
String description
static hasMany = [codeValues:CodeValue]
}
Поиск CodeValues занимал> 17 секунд. Я проиндексировал более 1000 объектов CodeValue, но 17-секундное время поиска было неприемлемым. Я выяснил, что вызывает медленное время поиска, и это, похоже, связано с функциональностью Compass, встроенной в плагин Grails Searchable.
В рамках поиска все сопоставленные объекты маршалируются в индекс. Для набора объектов Домена в сотнях время выполнения этого маршалинга не так уж и плохо, однако, когда вы попадаете в 1000-е, это занимает значительное количество времени. Возможно, время также связано со сложностью объекта, который выстраивается? В любом случае, я нашел сообщение в блоге от парня, у которого была такая же проблема, как и у меня.
Подводя итог статьи, когда он искал более 1000 объектов, время поиска было больше 15 секунд. Так же, как то, что я испытывал.
Он упомянул две вещи:
1) Установите для параметра supportUnmarshall значение false, значение по умолчанию - true, в конфигурации "статический поиск" в доменном объекте. При установке этой опции результаты поиска не попадают в индекс, однако время поиска очень быстрое. Снижение значения этой опции до false означает, что результаты не будут содержать объекты, не маршалируемые из индекса, и вам придется извлечь соответствующий объект домена из базы данных, используя идентификатор, возвращаемый как часть результата поиска. Вы могли бы подумать, что это будет плохо, но это не так, и при использовании этого метода мои результаты поиска отображаются намного быстрее, чем раньше. Вот URL для информации о настройке опции supportUnmarshall http://grails.org/Searchable+Plugin+-+Mapping+-+Class+Mapping. Это последний вариант в разделе "Опции".
2) Включите "перезагрузку" в defaultMethodOptions конфигурационного файла Searchable.groovy. Поэтому поместите что-то вроде этого в файл Searchable.groovy:
defaultMethodOptions = [
search: [reload: true, escape: false, offset: 0, max: 25, defaultOperator: "and"],
suggestQuery: [userFriendly: true]
]
Вам нужно будет добавить плагин Searchable Config, чтобы обновить это значение. Подробную информацию о добавлении и редактировании файла конфигурации Searchable.groovy можно найти на веб-странице плагина Grail Searchable. Поскольку у меня нет достаточно высокой репутации. Я не могу опубликовать более двух ссылок, поэтому вам нужно перейти на веб-страницу для плагина Grails Searchable и найти документацию по установке плагина Searchable Config.
Чтобы привести пример улучшения производительности. Ранее поиск по CodeValues занимал 17+ секунд. Теперь они выполнены за 0,002 секунды.
Окончательный код, который я написал, выглядел так:
class CodeValue{
static searchable ={
only:['value', 'description']
value boost: 2.0
supportUnmarshall false
}
String value
String description
static belongsTo = [codeset: CodeSet]
}
class CodeSet{
static searchable ={
only:['name', 'description']
name boost: 2.0
supportUnmarshall false
}
String name
String description
static hasMany = [codeValues:CodeValue]
}