2014-06-18 25 views
9

Chcę pobrać losowe rekordy przy użyciu Spring data JPA. Używałem @Query do tego samego.Ale to zajmuje dużo czasu.Pobieranie losowych rekordów przy użyciu danych Spring JPA

@Query("select que from Question que order by RAND()") 
public List<Question> findRandamQuestions(); 

Jaki jest skuteczny sposób robienia tego samego? Proszę o pomoc!

Odpowiedz

3

Możesz to zrobić po pobraniu.

Uzyskaj listę wszystkich pytań i po prostu uzyskaj losowe z nich.

public List<Question> getRandomQuestions(List<Questions> questions, int numberOfQuestions) { 
    List<Question> randomQuestions = new ArrayList<>(); 
    List<Question> copy = new ArrayList<>(questions); 

    SecureRandom rand = new SecureRandom(); 
    for (int i = 0; i < Math.min(numberOfQuestions, questions.size()); i++) { 
     randomQuestions.add(copy.remove(rand.nextInt(copy.size())); 
    } 

    return randomQuestions; 
} 

Lub, jeśli lista była naprawdę duża i wiedział identyfikatory wcześniej, można zrobić to samo i po prostu pobrać identyfikatory pytań, które potrzebne.

0

AFAIK nie ma na to wsparcia w Spring Data. IMHO, najlepszym sposobem działania jest utworzenie zapytania natywnego, np. @Query(nativeQuery=true, value="SELECT * FROM question ORDER BY random() LIMIT 10") przy użyciu natywnej metody sortowania PostgreSQL random() lub jej odpowiednika w DB.

5

Problem z select que from Question que order by RAND() polega na tym, że twój DB zamawia wszystkie zapisy przed zwróceniem jednego przedmiotu. Jest więc drogi w dużych zbiorach danych.

Tańszy sposób, aby osiągnąć ten cel składa się w dwóch etapach:

  1. Find sumie zapisów skąd można wybrać jedną.
  2. Zdobądź losowy przedmiot w tym zestawie.

Aby to zrobić w MySQL, na przykład, można zrobić:

select count(*) from question; 

// using any programming language, choose a random number between 0 and count-1 (let's save this number in rdn), and finally 

select * from question LIMIT $rdn, 1; 

Ok, ale aby to zrobić w danych sprężyny trzeba utworzyć kilka rodzimych zapytań ...

szczęście możemy użyć podziału na strony, aby to rozwiązać. W repozytorium interfejsu, tworzenie metod (niektóre repozytoria ma to bez konieczności jej określić):

Long count(); 
Page<Question> findAll(Pageable pageable); 

I w usłudze możesz użytkownik repozytorium w następujący sposób:

public Question randomQuestion() { 
    Long qty = questionRepository.countAll(); 
    int idx = (int)(Math.random() * qty); 
    Page<Question> questionPage = questionRepository.findAll(new PageRequest(idx, 1)); 
    Question q = null; 
    if (questionPage.hasContent()) { 
     q = questionPage.getContent().get(0); 
    } 
    return q; 
} 
+0

Jest to jeden tych doskonałych odpowiedzi, gdzie (a) to jest dokładnie to, czego potrzebowałem i (b) Google i ja nie byliśmy w stanie znaleźć niczego innego, co mogłoby zamknąć się zdalnie. Ale myślę, że masz literówkę: nie powinien "countAll()" być "count()"? – fivedogit

Powiązane problemy