Стратегия локализованной сортировки с нумерацией страниц - PullRequest
2 голосов
/ 20 августа 2009

Я работаю над приложением, которое развернуто в Интернете. Частью приложения являются функции поиска, где результат представлен в отсортированном списке. Приложение предназначено для пользователей в нескольких странах, используя разные локали (= правила сортировки). Мне нужно найти решение для правильной сортировки для всех пользователей.

В настоящее время я сортирую с ORDER BY в моем запросе SQL, поэтому сортировка выполняется в соответствии с языковым стандартом (или LC_LOCATE), установленным для базы данных. Эти правила некорректны для пользователей с языком, отличным от заданного для базы данных.

Кроме того, чтобы еще больше усложнить проблему, я использую нумерацию страниц в приложении, поэтому, когда я запрашиваю базу данных, я запрашиваю строки 1–15, 16–30 и т. Д., В зависимости от страницы, которая мне нужна. Однако, поскольку сортировка неверна, каждая страница содержит неправильно отсортированные записи. В худшем случае весь набор результатов для данной страницы может быть не в порядке, в зависимости от локали / правил сортировки текущего пользователя.

Если бы мне пришлось отсортировать код (на стороне сервера), мне нужно извлечь все строки из базы данных, а затем отсортировать. Это приводит к огромному снижению производительности, учитывая объем данных. Поэтому я бы хотел этого избежать.

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

Технические подробности: База данных PostgreSQL 8.3, приложение EJB3, использующее EJB QL для запроса данных, работающее на JBoss 4.5.

Ответы [ 5 ]

2 голосов
/ 21 января 2010

Готовы ли вы разработать небольшой пользовательский функциональный модуль Postgres на C? (Возможно, только несколько дней для опытного программиста на C).

strxfrm() - это функция, которая преобразует текстовую строку, зависящую от языка, на основе текущей настройки LC_COLLATE (более или менее текущего языка) в преобразованную строку, которая приводит к правильному порядку сортировки на этом языке, если она сортируется как двоичный байт последовательность (например, strcmp()).

Если вы реализуете это для Postgres, скажем, что он принимает строку и порядок сопоставления, то вы сможете упорядочить по strxfrm (textfield, collation_order). Я думаю, что вы можете даже создать несколько функциональных индексов в своем текстовом столбце (скажем, по одному на язык), используя эту функцию для хранения результатов strxfrm (), чтобы оптимизатор использовал индекс.

В качестве альтернативы, вы могли бы присоединиться к разработчикам Postgres для реализации этого в основном Postgres. Вот вики-страницы об этой проблеме: Сличения , ICU (насколько я знаю, также используется Java).


В качестве альтернативы, в качестве менее сложного решения, если ввод данных осуществляется только через Java, вы можете вычислить эти значения strxfrm () в Java (Java, вероятно, будет иметь другое имя для этой концепции) при добавлении данных в базу данных и затем позвольте индексу Postgres и упорядочите их по предварительно вычисленным значениям.

0 голосов
/ 05 мая 2010

Этот модуль не работает для Postgres 8.4.3. Я исправил это - вы можете скачать фиксированную версию с http://www.itreport.eu/__cw_files/.01/.17/.ee7844ba6716aa36b19abbd582a31701/nls_string.c, и вам придется скомпилировать и установить ее вручную (как описано в соответствующих разделах README и INSTALL из исходного модуля), но в любом случае сортировка работает неправильно. Я попробовал это на FreeBSD 8.0, LC_COLLATE - это cs_CZ.UTF-8

0 голосов
/ 21 января 2010

Возможно, вы захотите оформить этот пакет: http://www.fi.muni.cz/~adelton/l10n/postgresql-nls-string/. Он не обновлялся долгое время и может больше не работать, но это кажется разумной отправной точкой, если вы хотите создать функцию, которая может сделай это для тебя.

0 голосов
/ 20 августа 2009

Я не знаю, как переключить порядок базы данных order by. Поэтому нужно рассмотреть другие решения.

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

Особенно, использование кеша может значительно улучшить ситуацию. Первый запрос к базе данных (без ограничений) будет не намного медленнее, чем для запроса с ограниченным числом результатов. И последующие запросы будут намного быстрее. Зачастую пейджинг и повторная сортировка выполняются по нескольким запросам, поэтому кэш будет работать хорошо (даже с продолжительностью в несколько минут).

Я использую EhCache в качестве технического решения. Сортировка и подкачка идут вместе, сортировка и подкачка. Необработанные результаты могут быть сохранены в кеше.

Чтобы уменьшить удар по производительности, некоторые подсказки:

  • вы можете выполнить запрос один раз для размер набора результатов и предупредить пользователя, если результатов слишком много (запросите подтверждение медленного запроса или добавьте несколько полей выбора)
  • запрашивать только те столбцы, которые вам нужны , отпустить все остальные столбцы (обычно некоторые данные отображаются не сразу для всех результатов, а отображаются, например, при перемещении мыши; эти данные можно запрашивать лениво, только как необходимо, поэтому уменьшая количество столбцов, запрашиваемых для всех результатов)
  • если у вас есть вычисленные значения , кэшируйте меньшее между столбцами базы данных и вычисленными значениями
  • если у вас есть повторяющиеся значения в нескольких результатах, вы можете запросить эти данные / столбцы отдельно (чтобы вы извлекали из базы данных один раз, а кэшировали их только один раз), извлекали только ключ (обычно и id) в основном запросе.
0 голосов
/ 20 августа 2009

Насколько вы связаны с PostgreSQL? Документация не обещает:

Природа некоторых категорий языковых стандартов заключается в том, что их значение должно быть зафиксировано в течение всего времени жизни кластера базы данных. То есть после запуска initdb вы уже не сможете их изменить. LC_COLLATE и LC_CTYPE - это те категории. Они влияют на порядок сортировки индексов, поэтому они должны оставаться фиксированными, иначе индексы в текстовых столбцах будут повреждены. PostgreSQL обеспечивает это, записывая значения LC_COLLATE и LC_CTYPE, которые видит initdb. Сервер автоматически принимает эти два значения при запуске.

(Правила сортировки определяют порядок сортировки текста.)

Google выкидывает обсуждаемый патч :

В настоящее время PostgreSQL поддерживает только одно сопоставление за раз, что фиксируется переменной LC_COLLATE во время инициализации кластера базы данных.

Я не уверен, что хотел бы управлять этим вне базы данных, хотя мне было бы интересно прочитать о том, как это можно сделать. (Любой, кому нужен хороший технический обзор проблем, должен проверить Сортировка лингвистических данных в базе данных Oracle на сайте глобализации Oracle .)

...