Нужен совет по оптимизации запросов Lucene - PullRequest
3 голосов
/ 02 января 2009

Я работаю над приложением поиска работы через Интернет, используя Lucene. Пользователь на моем сайте может искать вакансии, которые находятся в радиусе 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 ]

3 голосов
/ 12 июня 2009

Не совсем уверен, полностью ли я понимаю ваш код, но когда дело доходит до геопространственного поиска, подход фильтра может быть более подходящим. Может быть, эта ссылка может дать вам некоторые идеи - http://sujitpal.blogspot.com/2008/02/spatial-search-with-lucene.html

Возможно, вы можете использовать Фильтр s и для других частей вашего запроса. Если честно, ваш запрос выглядит довольно сложным.

- Hardy

0 голосов
/ 06 ноября 2009

Согласитесь с другими здесь, что это пахнет слишком сильно. Кроме того, текстовый поиск по названиям городов не всегда так надежен. Между географическими названиями часто существует некоторая субъективность (особенно в пределах городов, которые сами по себе могут быть большими). ​​

Выполнение гео-пространственного запроса - это путь. Не зная остальной части вашей установки, трудно советовать. У вас есть пространственная поддержка, встроенная в Fluent to NHibernate и SQL Server 2008, например. Затем вы можете быстро и эффективно выполнить поиск очень . Однако ваша задача - заставить это работать в Lucene.

Возможно, вы могли бы выполнить запрос «первый проход», используя пространственную поддержку в SQL Server, а затем запустить эти результаты через Lucene?

Другим важным преимуществом выполнения пространственных запросов является то, что вы можете легко сортировать результаты по расстоянию, что является выгодой для ваших клиентов.

0 голосов
/ 26 июня 2009

Я бы предложил:

  • хранение широты и долготы местоположений по мере их поступления
  • когда пользователь вводит город и расстояние, поверните его в значение широта / долгота и градусы
  • сделать один простой поиск на основе числовых сравнений широт / расстояний

Вы можете увидеть пример того, как это работает в Perl-модуле Geo :: Distance . Взгляните на метод closest в source , который реализует этот поиск с помощью простого SQL.

0 голосов
/ 13 июня 2009

Я считаю, что лучший подход - это перенести определение ближайшего города в поисковый фильтр. Я также пересмотрю, как у вас есть полевые настройки; рассмотрите возможность создания одного термина с городом + государством, чтобы упростить запрос.

0 голосов
/ 10 июня 2009

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

0 голосов
/ 02 января 2009

Кроме того, что tempFinalQuery не используется и ненужного поиска карты для получения состояния, в коде, который вы публикуете, нет ничего слишком вопиющего. Помимо форматирования ...

Если все время занято в методах Parse, размещение кода здесь имеет смысл.

...