How to maintain lists of “most popular” products for each product category in a web application?

I need to save lists of the 40 most recently added, most popular / most popular items for each product category (total categories about 2000) in my application. I save the number of views and no for each item. For this, I want probably to support the memory structure on the application server in order to save and get a list of these elements.

Do you have any ideas on how to implement this data structure in memory, and, what is important, taking into account the amount of memory associated with it and minimizing it to the most distant extent)?


Using:

Java 1.6

+5
source share
4

, , , . . , . , .

In-Memory

Apache , , , - memcached. , , ( "topforty" ). Memcached , . .

, , . . - cron . , , , memcached, .

-, , :

public interface PopularityService {
  public List<Item> getTopItems(int count);//gets n top items

  //lets the service know someone liked a thing
  public void registerLike(Item item, Person liker);

  //lets the service know someone viewed a 
  public void registerView(Item item, Person viewer);thing
}

:

public class PopularStuff {
  public List<Item> popularItems
  ...
}

( , ). , , , . , , , , -, . - Hibernate, .

, , , , . , .

+7

Priority Queue? , , . , . , , .

+4

, , , , " ", , (.. SQL ). , , , , . ?

, , . , , . , , :

class TopXCache extends Runnable
{
  Object[] cachedData;

  int secondsToTimeOut;
  String sqlQueryToRefreshCache;

  boolean killSwitch = false;

  constructor(int itemsToKeepInCache, int secondsToTimeOut, String sqlQueryToRefreshCache)
  {
     this.secondsToTimeOut = secondsToTimeOut;
     this.sqlQueryToRefreshCache = sqlQueryToRefreshCache;

     this.cachedData = new Object[itemsToKeepInCache];
  }

  void run() // The method the thread will execute
  {
     while(!killSwitch) // Allows for "poison pill" shutdown
     {
       cachedData = executeQuery(sqlQueryToRefreshCache);
       wait(secondsToTimeOut);
     }
  }

  void kill()
  {
     killSwitch = true;
  }
}

, (secondsToTimeOut), SQL- , (sqlQueryToRefresh) , (itemsToKeepInCache, , 40).

, ( cron, , ), . , .

. , , , forceRefresh() , .

- , , , .

+3
source

I make the same assumption @Erica, but provide a different solution:

also suggested that the position category attitude is ambiguous.

import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import javax.ejb.EJB;

@ManagedBean
@RequestScoped
public class ItemBean
{
    @EJB
    private DbService dbService;

    @ManagedProperty("#{categoryCache}")
    private CategoryCache cache;

    public void incrementViewCounter(Item item)
    {
        item.setViewCount(item.getViewCount() + 1);
        dbService.update(item);
        cache.update(item);
    }

    public void incrementLikeCounter(Item item)
    {
        item.setLikeCount(item.getViewCount() + 1);
        dbService.update(item);
        cache.update(item);
    }
}


@ManagedBean
@ApplicationScoped
class CategoryCache
{
    private Map<Integer, ItemSet> categoryMap;

    public void update(Item item)
    {
        ItemReference ref = new ItemReference(item);

        for(Category c : item.getCategoryList())
        {
            ItemSet set = categoryMap.get(c.getId());
            if(set == null)
            {
                set = new ItemSet();
                categoryMap.put(c.getId(), set);
            }

            set.add(ref);
        }
    }
}

class ItemSet extends TreeSet<ItemReference>
{
    private static final int MAX_ENTRIES = 40;

    @Override
    public boolean add(ItemReference ref)
    {
        if(contains(ref)) remove(ref);

        super.add(ref);

        if(size() > MAX_ENTRIES)
        {
            remove(last());
        }

        return true;
    }
}

class ItemReference implements Comparable<ItemReference>
{
    private final Integer id;
    private final Double rank;

    public ItemReference(Item item)
    {
        this.id = item.getId();
        this.rank = item.getViewCount().doubleValue() * 0.1 + item.getLikeCount().doubleValue();
    }

    @Override
    public int compareTo(ItemReference that)
    {
        return -this.getRank().compareTo(that.getRank());
    }

    @Override
    public int hashCode()
    {
        return id.hashCode();
    }

    @Override
    public boolean equals(Object that)
    {
        if(that instanceof ItemReference)
        {
            return this.getId().equals(((ItemReference)that).getId());
        }

        return false;
    }

    public Integer getId()
    {
        return id;
    }

    public Double getRank()
    {
        return rank;
    }
}
0
source

All Articles