在搜索系统中,如何缓存搜索最频繁的1000个搜索结果?自定制的精准短文本搜索服务项目代码
本文利用了ConcurrentHashMap和AtomicLong实现了线程安全且支持高并发的最频繁访问驻留缓存算法,除了缓存功能,还提供了缓存状态查询接口,非常实用。
比如,在搜索管理界面可看到如下缓存状态:
缓存状态
最大缓存数量: 1000
当前缓存数量: 11
驱逐缓存次数: 0
命中缓存次数: 6
未命中缓存次数: 11
缓存命中比例: 35.294117 %
搜索缓存命中情况(11)
1 | L | 3 |
2 | LYB | 2 |
3 | LY | 1 |
4 | LANGYB | 0 |
5 | X | 0 |
6 | LANG | 0 |
7 | XL | 0 |
8 | LAN | 0 |
9 | XLF | 0 |
10 | LANGY | 0 |
11 | XLFD | 0 |
实现代码如下:
import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; /** * 最频繁访问驻留缓存算法 * Created by ysc on 7/18/16. */ public class ConcurrentLRUCache<K, V> { private int maxCacheSize; private Map<K, CacheItem<V>> cache = new ConcurrentHashMap<>(); private AtomicLong totalEvictCount = new AtomicLong(); private AtomicLong hitCount = new AtomicLong(); private AtomicLong notHitCount = new AtomicLong(); public ConcurrentLRUCache(int maxCacheSize) { cache = new ConcurrentHashMap<>(maxCacheSize, 1, 10); this.maxCacheSize = maxCacheSize; } public String getStatus(){ StringBuilder status = new StringBuilder(); long total = hitCount.get()+notHitCount.get(); status.append("最大缓存数量: ").append(maxCacheSize).append("\n") .append("当前缓存数量: ").append(getActualCacheSize()).append("\n") .append("驱逐缓存次数: ").append(totalEvictCount.get()).append("\n") .append("命中缓存次数: ").append(hitCount.get()).append("\n") .append("未命中缓存次数: ").append(notHitCount.get()).append("\n") .append("缓存命中比例: ").append(total == 0 ? 0 : hitCount.get()/(float)total*100).append(" %\n"); return status.toString(); } public String getKeyAndHitCount(){ StringBuilder status = new StringBuilder(); AtomicInteger i = new AtomicInteger(); cache.entrySet().stream().sorted((a,b)->b.getValue().getCount()-a.getValue().getCount()).forEach(entry->status.append(i.incrementAndGet()).append("\t").append(entry.getKey()).append("\t").append(entry.getValue().getCount()).append("\n")); return status.toString(); } public int getMaxCacheSize() { return maxCacheSize; } public int getActualCacheSize() { return cache.size(); } public Map<K, CacheItem<V>> getCache() { return Collections.unmodifiableMap(cache); } public AtomicLong getTotalEvictCount() { return totalEvictCount; } public long getHitCount() { return hitCount.longValue(); } public long getNotHitCount() { return notHitCount.longValue(); } public void put(K key, V value){ if(cache.size() >= maxCacheSize){ // evict count int evictCount = (int)(maxCacheSize*0.1); if(evictCount < 1){ evictCount = 1; } totalEvictCount.addAndGet(evictCount); cache.entrySet().stream().sorted((a,b)->a.getValue().getCount()-b.getValue().getCount()).limit(evictCount).forEach(entry->cache.remove(entry.getKey())); return; } cache.put(key, new CacheItem<V>(value, new AtomicInteger())); } public V get(K key){ CacheItem<V> item = cache.get(key); if(item != null){ item.hit(); hitCount.incrementAndGet(); return item.getValue(); } notHitCount.incrementAndGet(); return null; } private static class CacheItem<V>{ private V value; private AtomicInteger count; public CacheItem(V value, AtomicInteger count) { this.value = value; this.count = count; } public void hit(){ this.count.incrementAndGet(); } public V getValue() { return value; } public int getCount() { return count.get(); } } public static void main(String[] args) { ConcurrentLRUCache<Integer, Integer> cache = new ConcurrentLRUCache<>(5); for(int i=0; i<9; i++){ cache.put(i, i); if(i%2==0){ for(int j=0; j<i+2; j++){ cache.get(i); } } } System.out.println(cache.getStatus()); System.out.println(cache.getKeyAndHitCount()); } }
相关推荐
先进先出置换算法(FIFO):选择最先进入内存即在内存驻留时间最久的页面换出到外存。 最近最久未使用置换算法(LRU): 以“最近的过去”作为“最近的将来”的近似,选择最近一段时间最长时间未被访问的页面淘汰出...
b: 先进先出算法(FIFO):淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面予以淘汰。 c:最近最久未使用算法(LRU):淘汰最近最久未被使用的页面。 (3)程序采用人工的方法选择,依次换策略选择一个可置换...
页面置换算法实验报告包括:实验题目,实验目的,实验内容...2) 先进先出算法(FIFO):淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面予以淘汰。 3) 最近最久未使用算法(LRU):淘汰最近最久未被使用的页面。
第四章 实验四模拟先进先出(FIFO)页面置换算法置换策略:总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面予以淘汰。使用数组来模拟先进先出(FIF
该算法总是淘汰最先进入内存的页面,既选择在内存中驻留时间最久的页面予以淘汰。 LRU:最近最久未使用置换算法。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间T,当须淘汰一个...
多功能相控阵雷达实时驻留的自适应调度算法.pdf
为了解决大口径光学元件磁流变高精度加工问题,基于矩阵运算模型,提出了SBB...因此,提出的算法能够在有效保证面形收敛精度的同时快速获得稳定可靠的驻留时间分布,为磁流变抛光应用于大口径光学元件提供有力支持。
该算法总是淘汰最先进入内存的页面,即选择在内存中驻留时间最长的页面给予淘汰。该算法实现简单,只需要把一个进程已调入内存的页面,按先后次序连接成一个队列,并设置一个指针,称为替换指针,使它总是指向最老的...
一种含驻留粒子的改进粒子群算法.pdf
mean shift 目标跟踪算法,matlab程序源代码
操作系统实验七:内存页面置换算法实验报告。加深对于存储管理的了解,掌握虚拟存储器的实现原理;观察和了解重要的页面置换算法和置换过程。练习模拟算法的编程技巧,锻炼分析试验数据的能力。实验内容:在以上示例...
一种基于波束驻留的相控阵雷达自适应调度算法.pdf
基于驻留约束的半导体晶圆蚀刻系统实时调度算法.pdf
时光驻留器
1.最佳置换算法(OPT)(理想置换算法):所...2.先进先出置换算法(FIFO):优先淘汰最早进入的页面,亦即在内存中驻留时间最久的页面。 3.最近最久未使用(LRU)算法:选择最近最长时间未访问过的页面予以淘汰。
(1)输入一个逻辑页面访问序列和随机产生逻辑页面访问序列,由四个线程同时完成每个算法; (2)能够设定驻留内存页面的个数、内存的存取时间、缺页中断的时间、快表的时间,并可以暂停和继续系统的执行; (3)...
随着5G SA的大规模商用,WZ YD已建站5000+,一二期已完成建设,正在投入三期建设中,随着5G用户的发展,用户的感知也显得尤为重要,其中“占得上”为最基本的需求,由于5G流量尚未形成规模,时长驻留比为重点关注的...
时光驻留器是一款让软件获取固定时间的软件,该软件可以对软件下所有程序做时光驻留,操作简单,效果极佳,可以免费驻留一个软件,让您体验时光魔法师的神奇魅力。 前面都是废话,很多软件都可以使用这个工具来达到...