First of all, I think this problem is too difficult to be solved by using a Hibernate query, or even a set of Hibernate queries.
Here's how I would do:
- load all 100 questions in memory
- create a
Map<Field, List<Question>>
, and shuffle all the lists in this map
- for each field, take the first question of the corresponding list that has an acceptable level
- Once you have one question in every field, take all the remaining questions, put them in a list, shuffle the list, and iterate over the list. Each time a question has a level which is acceptable, take it. Do that until you have your 20 questions.
This should work if, for each field, you're guaranteed to have at least a question for every level. If it's not the case, then it's more difficult.
If you have much more questions that 100, and they can't be loaded in memory, you could use the same kind of algorithm, but use random queries to select the questions:
- issue one query per field to find a question in each field. The where clause should only accept the given field, and should only accept the levels which are still acceptable.
- issue a query to find N questions randomly (with N being equal to 50, for example, and with a where clause which only accepts the remaining levels), and take the first 10 acceptable questions. If there are less than 10 acceptable questions, try again. There should be at most 3 such queries. Make sure your where clause rejects the IDs of the questions which have already been loaded.