2016-05-31 3 views
1

선택한 요일의 평균 점유율을 계산해야합니다 (예 : 모든 금요일 - 매분). Date/Time 기능이 없기 때문에이 문제에 대한 JPQL/Querydsl 솔루션을 찾지 못했습니다. 그래서 Java Streams를 사용하려고합니다. 내 (간체) 목적 :Java 스트림을 사용하여 JPA 저장소에서 필드를 그룹화하고 평균화하고 새 컬렉션에 넣는 방법

class Occupancy { 
    private LocalDateTime timeStamp; 
    private int occupied; 
} 

내 REPO :

@Query("select o from Occupancy o") 
public Stream<Occupancy> streamAllOccupancies(); 

샘플 :

try (Stream<Occupancy> stream = repository.streamAllOccupancies()) { 

    Function<Occupancy,LocalTime> OccupancyMinutesGrouping = (Occupancy o) -> { 
     return o.getDateTime().toLocalTime().truncatedTo(ChronoUnit.MINUTES); 
    }; 


    Map<LocalTime,Double> avgMap = stream 
     .filter(o -> o.getDateTime().getDayOfWeek() == DayOfWeek.MONDAY) //example 
     .collect(
      Collectors.groupingBy(
       OccupancyMinutesGrouping, 
       Collectors.averagingInt(Occupancy::getOccupied) 
      ) 
     ); 
} 

의미가 있습니다 -하지만 내 점유율 객체의리스트에 가능한 변화들에게이지도를하다 :

new Occupancy(localTime, averagedOccupancy); 

나는 또한 스트림 효율성에 대한 걱정 - 데이터베이스의 모든 레코드를 처리해야합니다. 스트림은 jpa repo에서 어떻게 작동합니까? 첫 번째 SQL은 모든 레코드를 가져온 다음 스트림에서 처리합니다. 또는 모든 레코드에서 순차적으로 처리됩니까? 어쩌면 최고의 솔루션은 스트림의 기본 SQL 쿼리 insted를 사용하는 것입니까? 어떤 아이디어라도 도움이 될 것입니다 ...

답변

1

List<Occupancy>으로의 변환은 occupied 필드가 int 유형이며 평균은 비 필수 일 수 있습니다. 이제

class Occupancy { 
    private LocalDateTime timeStamp; 
    private double occupied; 

    public Occupancy(LocalDateTime ts, double occ) { 
     this.timeStamp = ts; 
     this.occupied = occ; 
    } 
} 

방금 ​​결과지도에서 또 하나 개의 스트림을 생성 할 수 있습니다 : 그래서 Occupancy 클래스가 이런 식으로 정의되어 있다고 가정

List<Occupancy> occupancies = avgMap.entrySet().stream() 
    .map(e -> new Occupancy(e.getKey(), e.getValue())) 
    .collect(Collectors.toList()); 

중간 Map는 (적어도 경우 어쩔 수없는 것 같다 스트림이 이미 LocalTime에 의해 정렬되지 않았습니다.)

메모리 사용량은 기본 JDBC 드라이버에 따라 다릅니다. 결과 스트림은 실제로 로우 단위의 ResultSet 행을 읽습니다. 그러나 JDBC는 몇 개의 로우가 한번에 프리 버퍼링되는지를 보여줍니다. 예를 들어, 기본적으로 MySQL의 드라이버가 메모리에 전체 ResultSet를 검색하는 것으로 알려져, 그래서 당신은이 같은 일부 쿼리 힌트해야 할 수 있습니다

@QueryHints(value = @QueryHint(name = HINT_FETCH_SIZE, value = "" + Integer.MIN_VALUE)) 

자세한 것은 this blog post를 참조하십시오.

또한 JDBC 드라이버가 실제로 서버에서 데이터를 버퍼링하지 않고 (데이터를 버퍼링하지 않고) 반입하는 경우 DBMS와 응용 프로그램간에 더 많은 왕복이 필요할 수 있으므로 실제로 성능이 저하 될 수 있습니다. DBMS 서버가 다른 시스템에있는 경우 특히 중요합니다.) 자세한 내용은 JDBC 드라이버 설명서를 참조하십시오.

+0

답장을 보내 주셔서 감사합니다. 물론 두 번째 스트림의 솔루션이 작동하지만 한 스트림 및 그룹 -> 평균을 사용하여 결과를 목록에 넣는 방법을 생각했습니다. 나는 H2를 개발에 사용하고있다. 그러나 자극적이다. 그것은 MySQL이 될 것입니다. 팁 주셔서 감사합니다. – Aragornx