#java #spring #spring-boot #hibernate
#java #весна #spring-boot #спящий режим
Вопрос:
Я пытаюсь выполнить поиск по нескольким атрибутам в запросе по спецификации в Spring Boot. Когда я ввожу одно слово для поиска, оно работает, но когда я ввожу два слова, оно не выдает правильный вывод.
Вот модель.
@Entity
@NoArgsConstructor
@Getter
@Setter
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "USER_ID")
private long id;
private String firstName;
private String surName;
private int age;
private Date dob;
private String description;
private String highestEducationQualification;
private String occupation;
private String employer;
private String college;
private String school;
private String eyecolor;
private double weight;
private double height;
private boolean driversLicence;
private boolean provisionalLicence;
private long phoneNumber;
private char gender;
private String emailAddress;
private String websiteAddress;
private String homeAddress;
private String image;
}
Вот репозиторий.
@Repository
public interface PersonRepo extends JpaRepository<Person, Long>, JpaSpecificationExecutor<Person> {
List<Person> searchByFirstNameContainingOrSurNameContainingAllIgnoreCase(String firstName, String surName);
Person findByFirstName(String firstName);
List<Person> searchByFirstNameContainingAllIgnoreCase(String firstName, Pageable page);
List<Person> searchBySurNameContainingAllIgnoreCase(String surName, Pageable page);
List<Person> searchByAge(int age, Pageable page);
List<Person> searchByDescriptionContainingAllIgnoreCase(String desc, Pageable page);
List<Person> searchByHighestEducationQualificationContainingAllIgnoreCase(String edu, Pageable page);
List<Person> searchByOccupationContainingAllIgnoreCase(String occ, Pageable page);
List<Person> searchByEmployerContainingAllIgnoreCase(String emp, Pageable page);
List<Person> searchByCollegeContainingAllIgnoreCase(String emp, Pageable page);
List<Person> searchBySchoolContainingAllIgnoreCase(String emp, Pageable page);
List<Person> searchByEyecolorContainingAllIgnoreCase(String eye, Pageable page);
List<Person> searchByWeight(double weight, Pageable page);
List<Person> searchByHeight(double height, Pageable page);
List<Person> searchByDriversLicence(boolean emp, Pageable page);
List<Person> searchByProvisionalLicence(boolean emp, Pageable page);
List<Person> searchByPhoneNumber(long phone, Pageable page);
List<Person> searchByGender(char emp, Pageable page);
List<Person> searchByEmailAddressIgnoreCase(String emp, Pageable page);
List<Person> searchByWebsiteAddressContainingAllIgnoreCase(String emp, Pageable page);
List<Person> searchByHomeAddressContainingAllIgnoreCase(String emp, Pageable page);
}
Вот сервис.
public List<Person> searchBySpecAll(String search, String page, String num, String sortBy, String ascending){
ArrayList<PersonSpecification> personSpecs = new ArrayList<PersonSpecification>();
ArrayList<String> searchWords = new ArrayList<String>();
for(String s : search.split(" ")) {
searchWords.add(s);
}
int numWords = searchWords.size();
System.out.println("num words");
for(String s : searchWords) {
System.out.println(s);
int age = 0;
try {
age = Integer.parseInt(s);
} catch (Exception e) {
}
double d = 0;
try {
d = Double.parseDouble(s);
} catch (Exception e) {
}
char gender = 0;
try {
gender = search.charAt(0);
} catch (Exception e) {
}
PersonSpecification spec = new PersonSpecification(new SearchCriteria("firstName", ":", s));
PersonSpecification spec2 = new PersonSpecification(new SearchCriteria("surName", ":", s));
PersonSpecification spec3 = new PersonSpecification(new SearchCriteria("age", ":", age));
PersonSpecification spec4 = new PersonSpecification(new SearchCriteria("description", ":", s));
PersonSpecification spec5 = new PersonSpecification(new SearchCriteria("highestEducationQualification", "=", s));
PersonSpecification spec6 = new PersonSpecification(new SearchCriteria("occupation", ":", s));
PersonSpecification spec7 = new PersonSpecification(new SearchCriteria("employer", ":", s));
PersonSpecification spec8 = new PersonSpecification(new SearchCriteria("college", ":", s));
PersonSpecification spec9 = new PersonSpecification(new SearchCriteria("school", ":", s));
PersonSpecification spec10 = new PersonSpecification(new SearchCriteria("eyecolor", "=", s));
PersonSpecification spec11 = new PersonSpecification(new SearchCriteria("weight", "=", d));
PersonSpecification spec12 = new PersonSpecification(new SearchCriteria("height", "=", d));
PersonSpecification spec17 = new PersonSpecification(new SearchCriteria("phoneNumber", "=", d));
//PersonSpecification spec18 = new PersonSpecification(new SearchCriteria("gender", "=", gender));
PersonSpecification spec19 = new PersonSpecification(new SearchCriteria("emailAddress", "=", s));
PersonSpecification spec20 = new PersonSpecification(new SearchCriteria("websiteAddress", ":", s));
PersonSpecification spec21 = new PersonSpecification(new SearchCriteria("homeAddress", ":", s));;
personSpecs.add(spec);
personSpecs.add(spec2);
personSpecs.add(spec3);
//personSpecs.add(spec4);
//personSpecs.add(spec5);
personSpecs.add(spec6);
personSpecs.add(spec7);
personSpecs.add(spec8);
personSpecs.add(spec9);
personSpecs.add(spec10);
personSpecs.add(spec11);
personSpecs.add(spec12);
personSpecs.add(spec17);
//personSpecs.add(spec18);
personSpecs.add(spec19);
personSpecs.add(spec20);
personSpecs.add(spec21);
}
int pageNum = 0;
try {
pageNum = Integer.parseInt(page);
} catch (Exception e) {
}
int numResults = 0;
try {
numResults = Integer.parseInt(num);
} catch (Exception e) {
}
boolean asc = true;
if(ascending.equals("false"))
asc = false;
Pageable firstPageWithFourElements = PageRequest.of(pageNum, numResults, Sort.by(Sort.Direction.DESC, sortBy));;
if(asc) {
firstPageWithFourElements = PageRequest.of(pageNum, numResults, Sort.by(Sort.Direction.ASC, sortBy));
}
ArrayList<Specification<Person>> specs = new ArrayList<Specification<Person>>();
Specification<Person> specTotal = null;
int numSpecs = 14;
int iters = personSpecs.size() / numSpecs;
System.out.println(personSpecs.size());
System.out.println("Iterations of personSpecs: " iters);
for(int i = 0; i < iters; i ) {
specs.add(Specification.where(personSpecs.get(i)).or(personSpecs.get(i 1)).or(personSpecs.get(i 2)).or(personSpecs.get(i 3)).or(personSpecs.get(i 4)).or(personSpecs.get(i 5)).or(personSpecs.get(i 6)).or(personSpecs.get(i 7)).or(personSpecs.get(i 8)).or(personSpecs.get(i 9)).or(personSpecs.get(i 10)).or(personSpecs.get(i 11)).or(personSpecs.get(i 12)).or(personSpecs.get(i 13)));
}
System.out.println("Number of specifications to append to total: " specs.size());
int totalToAppend = 0;
totalToAppend = specs.size();
System.out.print(totalToAppend);
switch(totalToAppend) {
case 1: {
specTotal = specs.get(0);
System.out.println(1 " case");
break;
}
case 2: {
specTotal = Specification.where(specs.get(0).and(specs.get(1)));
break;
}
case 3: {
specTotal = Specification.where(specs.get(0).and(specs.get(1)).and(specs.get(2)));
break;
}
case 4: {
specTotal = Specification.where(specs.get(0).and(specs.get(1)).and(specs.get(2)).and(specs.get(3)));
break;
}
}
//specTotal = Specification.where(spec).or(spec2).or(spec3).or(spec6).or(spec7).or(spec8).or(spec9).or(spec11).or(spec12).or(spec19).or(spec21).or(spec20).or(spec4).or(spec5).or(spec10).or(spec17);
Page<Person> results = personRepo.findAll(specTotal, firstPageWithFourElements);
List<Person> res = results.getContent();
return res;
}
Вы заметите, что функция работает, разбивая запрос на слова, если это необходимо. Повторяет каждое слово, создавая arraylist спецификаций для каждого слова. Затем он создал два Specification.where()
, обратившись к ранее созданным спецификациям в arraylist и объединив их в коммутаторе, в зависимости от количества слов, которое создает total Specification.where()
.
спецификация в зависимости от того, сколько слов было введено. Также поддерживается разбивка на страницы, сортировка и направление сортировки. Когда я ввожу одно слово, оно работает нормально. Но когда я ввожу два слова, это дает мне неверный вывод. Он показывает другого человека с фамилией, содержащей введенное слово поискового запроса.
Например.
Когда я ввожу «Adam» в качестве поискового запроса, он показывает мне мои личные данные. Но когда я ввожу «Адам Ховард», он показывает мне кого-то другого с именем Edi Adamiec. Я бы хотел, чтобы были выведены данные для Адама Ховарда. Я пытался использовать .or()` в «переключателе case 2» вместо and, но это не та функциональность, к которой я стремлюсь. Имя Edi Adamiec происходит от фиктивных данных в базе данных, для которых я использовал фиктивный генератор данных. Я мог бы предоставить данные базы данных, если это необходимо, просто дайте мне знать. Пожалуйста, ваша помощь приветствуется.
Вот сгенерированный SQL.
Hibernate: select person0_.user_id as user_id1_0_, person0_.age as age2_0_, person0_.college as college3_0_, person0_.description as descript4_0_, person0_.dob as dob5_0_, person0_.drivers_licence as drivers_6_0_, person0_.email_address as email_ad7_0_, person0_.employer as employer8_0_, person0_.eyecolor as eyecolor9_0_, person0_.first_name as first_n10_0_, person0_.gender as gender11_0_, person0_.height as height12_0_, person0_.highest_education_qualification as highest13_0_, person0_.home_address as home_ad14_0_, person0_.image as image15_0_, person0_.occupation as occupat16_0_, person0_.phone_number as phone_n17_0_, person0_.provisional_licence as provisi18_0_, person0_.school as school19_0_, person0_.sur_name as sur_nam20_0_, person0_.website_address as website21_0_, person0_.weight as weight22_0_ from person person0_ where (person0_.first_name like ? or person0_.home_address like ? or person0_.website_address like ? or person0_.email_address=? or person0_.phone_number=0 or person0_.height=0.0 or person0_.weight=0.0 or person0_.eyecolor=? or person0_.school like ? or person0_.college like ? or person0_.employer like ? or person0_.occupation like ? or person0_.age=0 or person0_.sur_name like ?) and (person0_.home_address like ? or person0_.website_address like ? or person0_.email_address=? or person0_.phone_number=0 or person0_.height=0.0 or person0_.weight=0.0 or person0_.eyecolor=? or person0_.school like ? or person0_.college like ? or person0_.employer like ? or person0_.occupation like ? or person0_.age=0 or person0_.sur_name like ? or person0_.first_name like ?) order by person0_.first_name asc limit ?
Я фактически хочу выполнять поиск по всем атрибутам, причем некоторые атрибуты представляют собой одно слово, в абзацах текста. Я хочу, чтобы поисковый запрос был разбит на слова, чтобы он мог выполнять поиск, например, по имени и фамилии.
Ответ №1:
Я думаю, проблема в том, что вы добавляете дизъюнкции, подобные person0_.weight=0.0
тем, которые верны для некоторых других людей. Попробуйте удалить их.
Комментарии:
1. Это хорошая мысль, но данные для другого пользователя, которые отображаются, не соответствуют вашему предложению. Нет значений 0 для веса или высоты или любого другого числового атрибута.
2. Какие параметры вы привязываете? Вы проверяли, могут ли некоторые параметры для подобных предикатов соответствовать нескольким строкам?
3. Даже если предикат like возвращает несколько строк, это не должно быть проблемой. Я получил несколько результатов с самого начала, и может произойти событие, когда поиск возвращает несколько пользователей, поэтому это должно быть частью функциональности. Но я не вижу, что вызывает поврежденные результаты, вероятно, это что-то настолько очевидное. Я забыл добавить спецификацию, я могу показать вам репозиторий github, если у вас есть время взглянуть.
4. github.com/mupml/person-search-spring-boot-vue-security
5. Я бы порекомендовал вам просмотреть сгенерированные SQL-запросы вместе со связанными параметрами и поиграть с этим, чтобы увидеть, что не так в логике. При беглом взгляде я могу сказать, что вы неправильно соединяете спецификации, т.Е. Вы должны использовать
(attr1 = ? OR attr2 = ?) AND (attr1 = ? OR attr2 = ?)
соединение для каждого поискового слова.