2014-06-18 38 views
9

Voglio recuperare i record casuali utilizzando i dati Spring JPA. Stavo usando @Query per lo stesso. Ma ci vuole molto tempo.Recupera record casuali utilizzando i dati Spring JPA

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

Qual è il modo efficace per fare lo stesso? Si prega di aiuto!

risposta

3

Si potrebbe fare questo recupero post.

Ottenere un elenco di tutte le domande e ottenere solo quelle casuali da quelle.

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; 
} 

O se l'elenco è stato davvero grande e si sapeva che gli ID in anticipo, si potrebbe fare la stessa cosa e solo recuperare i Ids Domande che avevi bisogno.

0

AFAIK non è supportato in Spring Data. IMHO, la cosa migliore da fare è creare una query nativa, ad es. @Query(nativeQuery=true, value="SELECT * FROM question ORDER BY random() LIMIT 10") utilizzando il metodo di ordinamento nativo random() di PostgreSQL o alcuni equivalenti nel DB.

5

Il problema con select que from Question que order by RAND() è che il DB ordinerà tutti i record prima di restituire un articolo. Quindi è costoso in grandi serie di dati.

Un modo più economico per raggiungere questo obiettivo consiste in due fasi:

  1. Find totale di record da dove si selezionarne uno.
  2. Ottieni un oggetto a caso in questo set.

di farlo in MySql, per esempio, si può fare:

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, ma per fare questo nei dati primavera è necessario creare alcune query native ...

Fortunatamente, possiamo usare l'impaginazione per risolverlo. Nell'interfaccia Repository, creare i metodi (alcuni repository ha questo senza bisogno di definirla):

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

E nel vostro servizio che potete utente repository nel seguente modo:

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

Questo è uno di quelle risposte perfette in cui (a) è * esattamente * ciò di cui avevo bisogno e (b) Google e io non siamo riusciti a trovare qualcos'altro da vicino. Ma penso che tu abbia un refuso: non dovrebbe "countAll()" essere "count()"? – fivedogit

Problemi correlati