Нужен совет по оптимизации запросов Lucene
Я работаю над приложением поиска работы через Интернет, используя Lucene.User. На моем сайте можно искать вакансии, которые находятся в радиусе 100 миль, скажем, от "Бостона, Массачусетса" или любого другого места. Кроме того, мне нужно показать результаты поиска, отсортированные по "релевантности"(т. Е. Оценка, возвращаемая lucene) в порядке убывания.
Я использую сторонний API для извлечения всех городов в заданном радиусе города. Этот API возвращает мне около 864 городов в радиусе 100 миль от "Бостона, Массачусетс".
Я создаю запрос Lucene для города / штата, используя следующую логику, которая является частью моего метода "BuildNearestCitiesQuery". Здесь nearCities - это хеш-таблица, возвращенная вышеуказанным API. Он содержит 864 города с ключом задницы CityName и StateCode в качестве значения. И finalQuery - это объект Lucene BooleanQuery, который содержит другие критерии поиска, введенные пользователем, такие как навыки, ключевые слова и т. Д.
foreach (string city in nearestCities.Keys)
{
BooleanQuery tempFinalQuery = finalQuery;
cityStateQuery = new BooleanQuery();
queryCity = queryParserCity.Parse(city);
queryState = queryParserState.Parse(((string[])nearestCities[city])[1]);
cityStateQuery.Add(queryCity, BooleanClause.Occur.MUST); //must is like an AND
cityStateQuery.Add(queryState, BooleanClause.Occur.MUST);
}
nearestCityQuery.Add(cityStateQuery, BooleanClause.Occur.SHOULD); //should is like an OR
finalQuery.Add(nearestCityQuery, BooleanClause.Occur.MUST);
Затем я вводю объект finalQuery в метод поиска Lucene, чтобы получить все задания в радиусе 100 миль.
searcher.Search(finalQuery, collector);
Я обнаружил, что этот метод BuildNearestCitiesQuery выполняется в среднем 29 секунд, что, очевидно, недопустимо по любым стандартам веб-сайта. Я также обнаружил, что операторы, включающие "Parse", выполняются в течение значительного времени по сравнению с другими заявления.
Работа для заданного местоположения является динамическим атрибутом в том смысле, что сегодня в городе может быть 2 работы (отвечающие определенным критериям поиска), но через 3 дня работа по тем же критериям поиска не выполняется. Поэтому я не могу использовать "Кэширование" здесь.
Есть ли способ, которым я могу оптимизировать эту логику или, если уж на то пошло, весь мой подход / алгоритм к поиску всех рабочих мест в радиусе 100 миль с помощью Lucene?
К вашему сведению, вот как выглядит моя индексация в Lucene:
doc.Add(new Field("jobId", job.JobID.ToString().Trim(), Field.Store.YES, Field.Index.UN_TOKENIZED));
doc.Add(new Field("title", job.JobTitle.Trim(), Field.Store.YES, Field.Index.TOKENIZED));
doc.Add(new Field("description", job.JobDescription.Trim(), Field.Store.NO, Field.Index.TOKENIZED));
doc.Add(new Field("city", job.City.Trim(), Field.Store.YES, Field.Index.TOKENIZED , Field.TermVector.YES));
doc.Add(new Field("state", job.StateCode.Trim(), Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.YES));
doc.Add(new Field("citystate", job.City.Trim() + ", " + job.StateCode.Trim(), Field.Store.YES, Field.Index.UN_TOKENIZED , Field.TermVector.YES));
doc.Add(new Field("datePosted", jobPostedDateTime, Field.Store.YES, Field.Index.UN_TOKENIZED));
doc.Add(new Field("company", job.HiringCoName.Trim(), Field.Store.YES, Field.Index.TOKENIZED));
doc.Add(new Field("jobType", job.JobTypeID.ToString(), Field.Store.NO, Field.Index.UN_TOKENIZED,Field.TermVector.YES));
doc.Add(new Field("sector", job.SectorID.ToString(), Field.Store.NO, Field.Index.UN_TOKENIZED, Field.TermVector.YES));
doc.Add(new Field("showAllJobs", "yy", Field.Store.NO, Field.Index.UN_TOKENIZED));
Спасибо большое за чтение! Я был бы очень признателен за вашу помощь в этом.
Janis
6 ответов
Не совсем уверен, полностью ли я понимаю ваш код, но когда дело доходит до геопространственного поиска, подход фильтра может быть более подходящим. Может быть, эта ссылка может дать вам некоторые идеи - http://sujitpal.blogspot.com/2008/02/spatial-search-with-lucene.html
Возможно, вы можете использовать Filter s для других частей вашего запроса. Если честно, ваш запрос выглядит довольно сложным.
--Hardy
Помимо tempFinalQuery
неиспользуемый и ненужный поиск карты для получения состояния, в коде, который вы публикуете, нет ничего слишком вопиющего. Помимо форматирования...
Если все время занято в Parse
методы, размещение их кода здесь имеет смысл.
Я бы предложил:
- хранение широты и долготы мест, когда они входят
- когда пользователь вводит город и расстояние, превратите его в значение широты / долготы и градусы
- сделать один простой поиск на основе числовых сравнений широт / расстояний
Вы можете увидеть пример того, как это работает в модуле Geo:: Distance Perl. Посмотрите на closest
метод в источнике, который реализует этот поиск с помощью простого SQL.
Возможно, я пропустил суть вашего вопроса, но есть ли у вас возможность сохранить широту и долготу для почтовых индексов? Если это вариант, вы можете рассчитать расстояние между двумя координатами, предоставив гораздо более простой показатель оценки.
Я считаю, что лучший подход - переместить определение ближайшего города в поисковый фильтр. Я также пересмотрю, как у вас есть полевые настройки; рассмотрите возможность создания одного термина с городом + государством, чтобы упростить запрос.
Согласитесь с другими здесь, что это пахнет слишком сильно. Кроме того, текстовый поиск по названиям городов не всегда так надежен. Между географическими названиями часто существует некоторая субъективность (особенно в пределах районов города, которые сами по себе могут быть большими).
Выполнение гео-пространственного запроса - это путь. Не зная остальной части вашей установки, трудно советовать. У вас есть пространственная поддержка, встроенная в Fluent to NHibernate и SQL Server 2008, например. Тогда вы могли бы сделать поиск очень быстро и эффективно. Однако ваша задача - заставить это работать в Lucene.
Возможно, вы могли бы выполнить запрос "первый проход", используя пространственную поддержку в SQL Server, а затем запустить эти результаты через Lucene?
Другим важным преимуществом выполнения пространственных запросов является то, что вы можете легко сортировать результаты по расстоянию, что является выгодой для ваших клиентов.