乐动体育官方正版网站

乐动体育下载

乐动体育下注大全 内存崩溃了?其实你只需要换一种花式

发布日期:2023-11-22 06:57    点击次数:157

乐动体育下注大全 内存崩溃了?其实你只需要换一种花式

 在上一篇Java多线程爬虫及散布式爬虫架构探索中,咱们使用了JDK自带的Set相聚来进行URL去重,看上去遵循可以,然则这种作念法有一个致命了残障,即是跟着网罗的URL增加,你需要的内存越来越大,最终会导致你的内存崩溃。那咱们在不使用数据库的情况下有莫得贬责办法呢?还难忘咱们在上一篇著述中提到的布隆过滤器吗?它就可以完好贬责这个问题,布隆过滤器有什么零碎的地点呢?接下来就一齐来学习一下布隆过滤器。

[[]]

什么是布隆过滤器

布隆过滤器是一种数据结构,相比奥密的概率型数据结构,它是在年由一个名叫布隆提议的,它试验上是由一个很长的二进制向量和一系列立地映射函数构成,这点跟哈希表有些交流,然则相对哈希表来说布隆过滤器它更高效、占用空间更少,布隆过滤器有一个污点那即是有一定的误识别率和删除贫寒。布隆过滤器只可告诉你某个元素一定不存在大约可能存在在麇妥洽,是以布隆过滤器宽泛用来处理可以隐忍判断诞妄的业务,比如爬虫URL去重。

布隆过滤器旨趣

在说布隆过滤器旨趣之前,咱们先来温习一下哈希表,在上一篇著述中,咱们哄骗的是Set来进行URL去重,咱们来望望Set的存储模子

 

 

 

Seturl去重

 

URL经由一个哈希函数后,将URL存入了数组里,这么查询时也诟谇常高效的,然则由于数组里存入的是URL,跟着URL的增加,需要的数组越来越大,意味着你需要更多的内存,比如咱们网罗了几亿的URL,那么可能就需要上百G的内存,这是要求不允许的,因为内存超过的不菲,是以这个在url去重中是不成取的,占内存更小的布隆过滤器即是一种可以的采取。

布隆过滤器骨子上由长度为m的位向量或位列表(仅包含或位值的列表)构成,领先扫数值均建造为,如下所示。

 

 

 

布隆过滤器

 

因为底层是bit数组,是以意味着数组唯一、两个值,跟哈希表相同,咱们将URL通过K个函数映射bit数组里,况且将指向的Bit数组对应的值改成。咱们以/nba/.html为例,如下图所示。

 

 

 

布隆过滤器

 

/nba/.html经由三个哈希函数区分映射到了、、的位置,这三个bit数组的值就形成了,咱们再存入一个/nba/.html,此时bit数组就形成底下这么:

 

 

 

布隆过滤器

 

/nba/.html被映射到了、、的位置,是以此时bit数组上有个位置的值为,本应该是有个值为的,然则因为在这个位置重叠了,是以会遮掩。

布隆过滤器是如何判断某个值一定不存在大约可能存在呢?通过判断哈希函数映射到对应数组的值,若是皆为,显露可能存在,若是有一个不为,显露一定不存在。对于一定不存在好融会,然则皆为时,为什么说可能存在呢?这跟哈希表相同,哈希函数会产生哈希突破,也即是说两个不同的值经由哈希函数皆会得到解除个数组下标,布隆过滤器亦然相同的。咱们以判断/nba/.html是否也曾网罗过为例,经由哈希函数映射的bit数组上的位置如下图所示:

 

 

 

布隆过滤器

 

 

 

/nba/.html被哈希函数映射到了、、的位置,而这几个位置的值皆为,是以布隆过滤器就以为/nba/.html被网罗过了,乐动体育下注大全试验上是莫得网罗过的,这就显露了布隆过滤器存在误判,这亦然咱们业务允许的。布隆过滤器的误判率跟bit数组的大小和哈希函数的个数相干系,若是bit数组过小,哈希函数过多,那么bit数组的值很快皆会形成,这么误判率就会越来越高,bit数组过大,就会破坏更多的内存,是以就要均衡好bit数组的大小和哈希函数的个数,对于如何均衡这两个的关系,不是咱们这篇著述的要点。

布隆过滤器的旨趣咱们也曾了解了,为了加深对布隆过滤器的融会,咱们用Java来已毕一个浅显版的布隆过滤器,代码如下:

public class SimpleBloomFilterTest {     // bit 数组的大小     private static final int DEFAULT_SIZE = ;     // 用来出产三个不同的哈希函数的     private static final int[] seeds = new int[]{, , ,};     // bit 数组     private BitSet bits = new BitSet(DEFAULT_SIZE);     // 存放哈希函数的数组     private SimpleHash[] func = new SimpleHash[seeds.length];     public static void main(String[] args) {         SimpleBloomFilterTest filter = new SimpleBloomFilterTest();         filter.add("");         filter.add("");         filter.add("");         System.out.println(filter.contains(""));         System.out.println(filter.contains(""));     }     public SimpleBloomFilterTest() {         for (int i = ; i < seeds.length; i++) {             func[i] = new SimpleHash(DEFAULT_SIZE, seeds[i]);         }     }     /**      * 向布隆过滤器添加元素      * @param value      */     public void add(String value) {         for (SimpleHash f : func) {             bits.set(f.hash(value), true);         }     }     /**      * 判断某元素是否存在布隆过滤器      * @param value      * @return      */     public boolean contains(String value) {         if (value == null) {             return false;         }         boolean ret = true;         for (SimpleHash f : func) {             ret = ret && bits.get(f.hash(value));         }         return ret;     }      /**      * 哈希函数      */     public static class SimpleHash {         private int cap;         private int seed;         public SimpleHash(int cap, int seed) {             this.cap = cap;             this.seed = seed;         }         public int hash(String value) {             int result = ;             int len = value.length();             for (int i = ; i < len; i++) {                 result = seed * result + value.charAt(i);             }             return (cap - ) & result;         }     } } 

把上头这段代码融会好对咱们融会布隆过滤器相当有匡助,试验上在使命中并不需要咱们我方已毕布隆过滤器,谷歌也曾帮咱们已毕了布隆过滤器,在Guava包中提供了BloomFilter,这个布隆过滤器已毕的相当棒,底下就望望谷歌办的布隆过滤器。

布隆过滤器Guava版

要使用Guava包下提供的BloomFilter,就需要引入Guava包,咱们在pom.xml中引入底下依赖:

<dependency>     <groupId>com.google.guava</groupId>     <artifactId>guava</artifactId>     <version>.-jre</version> </dependency

Guava中的布隆过滤器已毕的相当复杂,对于细节咱们就不去议论了,咱们就来望望Guava中布隆过滤器的构造函数吧,Guava中并莫得提供构造函数,而且提供了create设施来构造布隆过滤器:

public static <T> BloomFilter<T> create(     Funnel<? super T> funnel, int expectedInsertions, double fpp) {   return create(funnel, (long) expectedInsertions, fpp); } 

funnel:你要过滤数据的类型

expectedInsertions:你要存放的数据量

fpp:误判率

你只需要传入这三个参数你就可以使用Guava包中的布隆过滤器了,底下这我写的一段Guava布隆过滤器测试设施,可以编削fpp多出手几次,体验Guava的布隆过滤器。

public class GuavaBloomFilterTest {     // bit 数组大小     private static int size = ;     // 布隆过滤器     private static BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()), size, .);      public static void main(String[] args) {         // 先向布隆过滤器中添加  个url         for (int i = ; i < size; i++) {             String url = "" + i;             bloomFilter.put(url);         }         // 前个url不会出现误判         for (int i = ; i < size; i++) {             String url = "" + i;             if (!bloomFilter.mightContain(url)) {                 System.out.println("该 url 被网罗过了");             }         }         List<String> list = new ArrayList<String>();         // 再向布隆过滤器中添加  个 url ,在这 个中就会出现误判了         // 误判的个数为  * fpp         for (int i = size; i < size + ; i++) {             String url = "" + i;             if (bloomFilter.mightContain(url)) {                 list.add(url);             }         }         System.out.println("误判数目:" + list.size());     } } 

布隆过滤器的应用

缓存击穿

缓存击穿是查询数据库中不存在的数据,若是灵验户坏心模拟苦求许多缓存中不存在的数据,由于缓存中皆莫得,导致这些苦求短时辰内径直落在了DB上,对DB产生压力,导致数据库极度。

最常见的贬责办法即是收受布隆过滤器,将扫数可能存在的数据哈希到一个充足大的bitmap中,一个一定不存在的数据会被这个bitmap抑止掉,从而幸免了对底层存储系统的查询压力。底下是一段伪代码:

public String getByKey(String key) {     // 通过key获得value     String value = redis.get(key);     if (StringUtil.isEmpty(value)) {         if (bloomFilter.mightContain(key)) {             value = xxxService.get(key);             redis.set(key, value);             return value;         } else {             return null;         }     }     return value; } 

爬虫URL去重

爬虫是对url的去重,提神url重叠网罗,这亦然咱们这篇著述要点培育的内容

垃圾邮件识别

从数十亿个垃圾邮件列表中判断某邮箱是否垃圾邮箱乐动体育下注大全,将垃圾邮箱添加到布隆过滤器中,然后判断某个邮件是否是存在在布隆过滤器中,存在显露即是垃圾邮箱。





Powered by 乐动体育官方正版网站 @2013-2022 RSS地图 HTML地图

Copyright 站群 © 2013-2023 乐动体育 版权所有