Как заставить hibernate выполнять поиск значений с разными шаблонами?

#java #mysql #hibernate

#java #mysql #hibernate

Вопрос:

Прежде всего, вопрос не в игнорировании пробелов в начале или конце строк, чтобы это не было дубликатом.

У меня есть поле mobile в базе данных, значения которого представлены в разных форматах, таких как xxx xxx xxx, xxxxxxxxx, x xxx xxx xx и т.д., Как я могу настроить критерии hibernate для игнорирования шаблонов строк?

Например, допустим, число в базе данных равно 344 555 666

  344555666  is failed 
 344 555 666 is failed 
 344 is true (first three digits that do not have space in database!)
  

Однако нет сомнений в том, что указаны все числа, и все вышеупомянутые значения должны возвращать 344 555 666 в качестве своих результатов.

Другим примером может быть следующий:

Допустим, пользователь выполняет поиск по всем телефонным номерам, которые включают 12345; затем DB возвращает следующие результаты 12345678, 12345987 и 12345768 теперь мне нужно отформатировать эти три числа, которые возвращаются DB, прежде чем показывать пользователю.

Код

 ...
private String mobile;
....
  

Hibernate

 .add(Restrictions.ilike("user.mobile", number); 
  

Ответ PVR полезен, но как насчет того, если в будущем мне понадобится добавить новый формат, такой как XXX-XXX-XXX или X-XXXX-XXXX-XXXX? Пожалуйста, также обратите внимание, что существует только одно поле, которое пользователь использует для ввода значения поиска.

Комментарии:

1. ИМХО, вы подходите к проблеме не с той стороны. Даже если вы найдете способ, для каждого поиска потребуется полное сканирование базы данных. Вы должны попытаться нормализовать данные в базе данных во время записи или, по крайней мере, использовать пакетную обработку или повторно нормализовать ее регулярно. При поиске можно было бы использовать индексы, и приложение было бы намного более отзывчивым.

2. @SergeBallesta что вы подразумеваете под тем, что приложение будет намного более отзывчивым? как это нормализовать? существует только один столбец с именем mobile, и никакие два пользователя не будут иметь одинаковые номера мобильных телефонов.

3. Возможно, нормализация — неправильное слово (английский не мой родной язык). Я имел в виду, что вы должны записать все мобильные номера в одном формате (например: 123456789) в базе данных. Все ваши поисковые запросы будут проще и поэтому (немного) быстрее. Но запрос select с использованием индексов может быть на порядок быстрее, чем без индексов. И вам нужно, чтобы все ваши мобильные номера имели одинаковый формат, чтобы правильно их индексировать.

4. @SergeBallesta ок, понял тебя, но как сделать остальное? Я имею в виду, как отобразить их в связанном с ними шаблоне? должен ли я извлечь их все и отформатировать перед представлением пользователю?

Ответ №1:

Попробуйте использовать следующее..

 criteria.add(Restrictions.ilike(
user.mobile, number, MatchMode.ANYWHERE));
  

Редактировать :

Я имел в виду, что если формат no. в базе данных может быть только один из XXX XXX XXXX / XXXXXXXXXXXX, тогда нам нужно написать конкретную логику, которая проверяет доступность обоих форматов в базе данных.

число 1: в формате XXX XXX XXXX число 2: в формате XXXXXXXXXXXX

 criteria.add(Restrictions.or(Restrictions.ilike(
    user.mobile, number1, MatchMode.ANYWHERE),(Restrictions.ilike(
    user.mobile, number2, MatchMode.ANYWHERE)));
  

Комментарии:

1. Он по-прежнему показывает те же результаты, что и в вопросах.

2. Это формат хранения no. в базе данных может быть только два ie. ХХХ ХХХ ХХХХ / XXXXXXXXXXXX ??

3. Пожалуйста, взгляните на раздел редактирования

4. спасибо за ваш ответ, но как насчет того, если в будущем мне понадобится добавить новый формат, такой как XXX-XXX-XXX или X-XXXX-XXXX-XXXX? Пожалуйста, также обратите внимание, что существует только одно поле, в которое пользователь может вводить значения в разных форматах.

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

Ответ №2:

Сталкиваясь с такой проблемой, я обычно обращаю ее вспять. В настоящее время в одном столбце вашей базы данных ( mobile ) хранятся значения в разных форматах (xxx xxx xxx, xxxxxxxxx, x xxx xxx xx и т.д.), И выполнить поиск по этому столбцу сложно.

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

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

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

Когда вы хотите выполнить поиск, разрешите пользователю вводить любой формат того, что они хотят, и примените то же преобразование, которое вы применяете при вставке. Например, если пользователь вводит 123 456 789 or 123-456-789 или любой из ваших принятых форматов, в вашем коде для поиска преобразуйте его в 123456789 и выполняйте запрос с этим значением (используя индекс …)

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

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

Комментарии:

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

2. @Jack Я не понимаю, в чем проблема при отображении списка: вы показываете значения в том виде, в каком они хранятся в вашей базе данных. Вы только переформатируете входное значение для вставки, обновления или поиска.

3. Вы меня неправильно поняли, допустим, пользователь вводит номер мобильного телефона как 12345 (частичный, не отформатированный номер), затем DB возвращает следующие результаты 12345678, 12345987 и 12345768 теперь мне нужно отформатировать эти три числа, которые возвращаются DB, прежде чем показывать пользователю.

4. @Jack Извините, я не понял… я имел в виду, что если пользователь вводит 123-45, вы выполняете запрос с помощью ... LIKE '12345%' (но с помощью подготовленного оператора …), используя индекс . Но я советую вам не показывать список из 1000 значений в одном ответе, а использовать разбивку на страницы.

5. Это хорошая идея, под индексом вы подразумеваете наличие индекса в этом столбце базы данных?

Ответ №3:

вы пробовали Projections.sqlProjection

Вы можете использовать replace ЗАМЕНИТЬ(mobile, ‘ ‘) внутри

Комментарии:

1. что вы подразумеваете под заменой и sqlprojection? Я считаю, что проекция sql используется для указания полей результата,

Ответ №4:

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

Я уже выполнял форматирование номера телефона раньше, но решение, которое вы ищете, может быть сложным, если вам нужно выполнить поиск с использованием regex, я создам regex в коде и выполню поиск в базе данных. (В Oracle есть функция regex_like, возможно, вы захотите использовать ее вместо ilike из hibernate)

например, номер телефона от клиента 333 555 9999, номер телефона в базе данных: 3 33 555 9999

Создайте следующее регулярное выражение на основе того, что отправляет клиент:

 / (s-.)*3(s-.)*3(s-.)*3(s-.)*5(s-.)*5(s-.)*5(s-.)*9(s-.)*9(s-.)*9(s-.)*9(s-.dw)*/
  

Вы хотите сказать, что может быть много (.) точек, может ( s) пробелов, много (-) хифенов в номере телефона, заканчивающемся многими (. s- d w) (например: x234 или ext2342)

Комментарии:

1. Кажется, это было бы сложной задачей, как вы выполняли свои предыдущие задачи по форматированию номера телефона? моя база данных — mysql, а не oracle

2. Регулярное выражение, которое я сделал, — это проверка клиента, клиент обо всем заботится, оно отличается от вашего senario. Пользователь сохраняет то, что ему нравится, непосредственно перед представлением данных они будут отформатированы в соответствии со страной, в которой он находится.

3. тогда в моем случае какой вариант был бы наилучшим? Я использую mysql, а не Oracle. Должен ли я сохранить их все неформатированными и отформатировать их перед показом пользователям?

Ответ №5:

Согласно вашему разговору с PVR, кажется, что формат телефонного номера может быть любым. Платформа Hibernate основана на шаблонах. Он не может обрабатывать какой-либо формат самостоятельно. Желательно не включать критерии, основанные на номере телефона, в Hibernate. Вы должны выполнить весь свой запрос критериев без номера телефона, и после этого у вас должна быть Java-логика для фильтрации остальных результатов.

Однако лучшее решение — сделать ваш дизайн более надежным. Добавление ограничения на формат телефона — лучшая практика. Вы можете рассмотреть возможность добавления проверки для формата phone.

Ответ №6:

Вы можете написать свой собственный критерий, реализовав интерфейс Criterion. В вашем методе toSqlString просто используйте функцию replace вашей базы данных. AFAIK replace(str, needle, replacement) — это стандартная функция SQL99, поэтому она должна работать в современных СУБД.