0

I am working on a project where using JPA and the following code I am able to retrieve from DB a list of objects which consist the profile of a user. Each object is a two field object (word, frequency)

public class JpaUserprofilesDao implements UserProfilesDao {

@PersistenceUnit
private EntityManagerFactory emf;
EntityManager em;

public EntityManager getEntityManager() {
    return emf.createEntityManager();
}

@Transactional
@Override

 public List<Object[]> getUserProfiles(Long userId){       

    em = getEntityManager();
    try {

        List<Object[]> up =em.createQuery("SELECT up.userprofilesPK.word,  up.userprofilesPK.frequency  from Userprofiles up WHERE up.userprofilesPK.userid= :userid").setParameter("userid", userId).getResultList();

        return up;

    } finally {
        em.close();
    }        
 }
}

In another class of my project I am using the following block of code in order to put the above information in a Map and be able to manipulate it.

profileObject = peristanceservice.getUserProfiles(userId);
              for(Object[] s: profileObject ){                       
                   if(!tempList.contains(s[0].toString())){                          
                       bag.put( (String) s[0].toString(), Integer.parseInt(s[1].toString()) );
                       tempList.add(s[0].toString());                                                 
                   }        
                }

Even though I am getting the result it takes so long time to process the list of objects returned by the persistance service and putting them to the Map, that finally prove useless. Is there a way to get the Map directly from the persistance service?

Thank you in advance.

user2008973
  • 435
  • 3
  • 9
  • 22
  • maybe `SELECT NEW` could be of use. you would still get a List instead of a Map but you would have better typesafety. see http://stackoverflow.com/questions/2355728/jpql-create-new-object-in-select-statement-avoid-or-embrace – Max Fichtelmann Mar 16 '14 at 14:25
  • Building the map should be several orders of magnitude faster than executing the query and get the result as a List. Your measurements are probebly incorrect, and you're trying to optimize at the wrong place. Also, `Integer.parseInt(s[1].toString())` is useless. What you have in the array if already an Integer (it's of the same type as the `frequency` field in your entity). Same for – JB Nizet Mar 16 '14 at 14:25
  • @JBNizet I am sorry but I did not get your advice. Perhaps I didn't manage to convey my message through my description. I know that is a lot faster getting the result straight way in a map but this is exactly what I asked, because what I've tried to get it as a map instead of list did not work. In any case even as the way I posted I get absolutely correct results but I also need to manipulate data, but this `for(Object[] s: profileObject )` takes a very very long time since the length of the profileObject list is too large. Thank you. – user2008973 Mar 16 '14 at 14:35
  • What I'm saying is that if you actually measure the time every operation takes in the above code, you should get something like 100 milliseconds to execute the query, and a few microseconds to transform the list to a map. So the list to map transformation is 10000 times faster than executing the query. What takes time is the network round-trip to the database and the execution time in the database. Getting the result as a Map rather than a List won't change anything. If the above code is too slow, then you should tweak the query and the database indices. Not try to get the result as a map. – JB Nizet Mar 16 '14 at 14:39
  • @JBNizet Oh now I got it! Well, this is true and that was my first thought, but during debugging I realized that this for-loop was way less faster than data retrieval from DB. Perhaps, it's something else and I should investigate it further, I don't know.. – user2008973 Mar 16 '14 at 14:43
  • 1
    What can take time in your code is `tempList.contains(s[0].toString())`. If tempList is indeed of type `List`, it will be O(n), which makes the whole loop O(n^2). Make it a HashSet, and it will be O(1), making the whole loop O(n). Or remove this check completely, as it seems useless to me, given your description. – JB Nizet Mar 16 '14 at 14:47
  • @JBNizet You were so right! I removed the redundant check and now it runs quite fast. Thank you so much! – user2008973 Mar 16 '14 at 15:31

1 Answers1

0

this is not exactly what you want, but you can use it.

You can transform List to Map using Guava

Use Maps.uniqueIndex:

  Returns an immutable map for which the Map.values() are the given elements in the given order, and each key is the product of invoking a supplied function on its corresponding value.

Example:

Map<String,String> mappedRoles = Maps.uniqueIndex(yourList, new Function<String,String>() {
  public String apply(String from) {
    // do stuff here
    return result;
  }});
gstackoverflow
  • 36,709
  • 117
  • 359
  • 710