我需要在我的应用程序中维护每个项目类别(总类别约为2000)的最近添加的40个、最受欢迎/最受喜爱的项目列表。我确实存储了每个项目的浏览次数和点赞数。为此,我打算在应用服务器上维护一个内存结构,以存储和检索这些项目列表。
您有关于如何实现这种内存数据结构的任何想法,尤其要考虑相关的内存占用和将其最小化的重要性吗?
使用:Java 1.6
您有关于如何实现这种内存数据结构的任何想法,尤其要考虑相关的内存占用和将其最小化的重要性吗?
使用:Java 1.6
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
...
}
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;
}
}
我和 @Erica 有相同的假设,但提供了不同的解决方案:
我也假设项目-类别关系是多对多的。
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;
}
}
select *,(views*.10 + likes) as rank from vw_categories_with_decayed_views_and_likes order by rank desc limit 40
- lsl