Better fulltext search

This commit is contained in:
Patrick Haßel 2023-06-19 10:26:01 +02:00
parent 7970c16026
commit 83aacd2a8d
10 changed files with 65 additions and 15 deletions

View File

@ -4,7 +4,7 @@
import {getBaseUrl} from "./UrlHelper";
const PROD: boolean = true;
const PROD: boolean = false;
export const environment = {
production: false,

View File

@ -0,0 +1,37 @@
package de.ph87.homeautomation;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.function.Function;
public class RepositorySearchHelper {
public static <T, D> List<D> search(final String term, final JpaSpecificationExecutor<T> repository, final String fieldName, final Function<T, D> map) {
final Specification<T> specification = (root, query, criteriaBuilder) -> {
final Expression<String> field = criteriaBuilder.lower(root.get(fieldName));
final String term2 = term
.replaceAll("([a-zA-Z])([0-9])", "$1 $2")
.replaceAll("([0-9])([a-zA-Z])", "$1 $2")
.replaceAll("([A-Z])([A-Z])", "$1 $2")
.replaceAll("([a-z])([A-Z])", "$1 $2")
.toLowerCase(Locale.ROOT);
System.out.println(term2);
final List<Predicate> predicates = Arrays.stream(term2.split("\\s"))
.filter(word -> !word.isEmpty())
.map(word -> criteriaBuilder.like(field, "%" + word + "%"))
.toList();
return criteriaBuilder.and(predicates.toArray(Predicate[]::new));
};
final PageRequest pageRequest = PageRequest.of(0, 20, Sort.by(Sort.Direction.ASC, fieldName));
return repository.findAll(specification, pageRequest).stream().map(map).toList();
}
}

View File

@ -63,7 +63,7 @@ public class BulkController implements ISearchController {
@PostMapping("searchLike")
@Deprecated(since = "Use 'filter' instead", forRemoval = true)
public List<SearchResult> searchLike(@RequestBody final String term) {
return bulkReader.findAllDtoLike("%" + term + "%").stream().map(this::toSearchResult).toList();
return bulkReader.search(term).stream().map(this::toSearchResult).toList();
}
@GetMapping("findAll")

View File

@ -1,5 +1,6 @@
package de.ph87.homeautomation.bulk;
import de.ph87.homeautomation.RepositorySearchHelper;
import de.ph87.homeautomation.property.Property;
import de.ph87.homeautomation.web.NotFoundException;
import lombok.RequiredArgsConstructor;
@ -50,4 +51,8 @@ public class BulkReader {
return bulkRepository.findDistinctByEntries_Property(property);
}
public List<BulkDto> search(final String term) {
return RepositorySearchHelper.search(term, bulkRepository, "title", bulkMapper::toDto);
}
}

View File

@ -19,6 +19,8 @@ public class KnxGroupChannelOwnerService implements IChannelOwner {
private final KnxGroupReader knxGroupReader;
private final KnxGroupMapper knxGroupMapper;
@Override
public void requestUpdate(final Channel channel) {
knxGroupWriter.requestRead((KnxGroup) channel);
@ -36,21 +38,17 @@ public class KnxGroupChannelOwnerService implements IChannelOwner {
@Override
public KnxGroupDto toDto(final long id) {
return toDto(knxGroupReader.getById(id));
}
public KnxGroupDto toDto(final KnxGroup knxGroup) {
return new KnxGroupDto(knxGroup);
return knxGroupMapper.toDto(knxGroupReader.getById(id));
}
@Override
public List<KnxGroupDto> findAllDto() {
return knxGroupReader.findAll().stream().map(this::toDto).toList();
return knxGroupReader.findAll().stream().map(knxGroupMapper::toDto).toList();
}
@Override
public List<KnxGroupDto> findAllDtoLikeIgnoreCase(final String like) {
return knxGroupReader.findAllLike(like).stream().map(this::toDto).toList();
public List<KnxGroupDto> findAllDtoLikeIgnoreCase(final String term) {
return knxGroupReader.search(term);
}
}

View File

@ -1,5 +1,6 @@
package de.ph87.homeautomation.knx.group;
import de.ph87.homeautomation.RepositorySearchHelper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@ -17,6 +18,8 @@ public class KnxGroupReader {
private final KnxGroupRepository knxGroupRepository;
private final KnxGroupMapper knxGroupMapper;
public Optional<KnxGroup> getByAddress(final int main, final int mid, final int sub) {
return knxGroupRepository.findByAddressRaw(new GroupAddress(main, mid, sub).getRawAddress());
}
@ -33,4 +36,8 @@ public class KnxGroupReader {
return knxGroupRepository.findById(id).orElseThrow(RuntimeException::new);
}
public List<KnxGroupDto> search(final String term) {
return RepositorySearchHelper.search(term, knxGroupRepository, "name", knxGroupMapper::toDto);
}
}

View File

@ -1,12 +1,13 @@
package de.ph87.homeautomation.knx.group;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Optional;
public interface KnxGroupRepository extends CrudRepository<KnxGroup, Long> {
public interface KnxGroupRepository extends CrudRepository<KnxGroup, Long>, JpaSpecificationExecutor<KnxGroup> {
Optional<KnxGroup> findByAddressRaw(int rawAddress);

View File

@ -87,7 +87,7 @@ public class PropertyController implements ISearchController {
@Override
@PostMapping("searchLike")
public List<SearchResult> searchLike(@RequestBody final String term) {
return propertyReader.findAllDtoLike("%" + term + "%").stream().map(this::toSearchResult).toList();
return propertyReader.search(term).stream().map(this::toSearchResult).toList();
}
private SearchResult toSearchResult(final PropertyDto propertyDto) {

View File

@ -1,5 +1,6 @@
package de.ph87.homeautomation.property;
import de.ph87.homeautomation.RepositorySearchHelper;
import de.ph87.homeautomation.web.NotFoundException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -22,8 +23,8 @@ public class PropertyReader {
return propertyRepository.findAllByReadChannel_Id(readChannelId);
}
public List<PropertyDto> findAllDtoLike(final String like) {
return propertyRepository.findAllByTitleLikeIgnoreCase(like).stream().map(propertyMapper::toDto).toList();
public List<PropertyDto> search(final String term) {
return RepositorySearchHelper.search(term, propertyRepository, "title", propertyMapper::toDto);
}
public PropertyDto getDtoById(final long id) {

View File

@ -1,11 +1,12 @@
package de.ph87.homeautomation.property;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import java.util.List;
import java.util.Optional;
public interface PropertyRepository extends JpaRepository<Property, Long> {
public interface PropertyRepository extends JpaRepository<Property, Long>, JpaSpecificationExecutor<Property> {
Optional<Property> findByTitle(String title);