C++【位图/布隆过滤器—海量数据处理】

文章目录

  • 一、位图
    • (1)位图概念介绍
    • (2)简单模拟实现
    • (3)位图应用
  • 二、布隆过滤器
    • (1)关于布隆过滤器概念及介绍
    • (2)布隆过滤器的使用场景
    • (3)模拟实现
    • (4)布隆过滤器天生不支持删除reset
    • (5)BF总结
  • 三、海量数据处理
    • (1)问题1/2
    • (2)问题3/4
    • (3)问题3
  • 四、所有源码(含BF)

一、位图

(1)位图概念介绍

先看下面的一道题
1.有40亿个不重复的无符号整数,无序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。
如果我们放到哈希表或红黑树中或用排序和二分查找这两种方法。
前两种方法不可行,因为40亿个整数占用大约16G的内存空间,第一要排序需要先把数放到内存,只能用文件归并排,但是不能文件中不能搞二分查找即不能用下标去访问;第二如果放到红黑树但是同样放不进去,如果放到树里面,给一棵树查找一次,但是这里是很多数据,来一个树先读2G查找再释放掉,再来一个树放进去查,不断的查,与其这样不如读的时候判断一下没必要放树里面,直接暴力查找了,还有额外的消耗表里面的结点不光有数据还是有指针。所以上俩种方法不行主要原因就是内存不够

我们可以用一种直接定址法,我们可以最少用1字节即char标记一个数在不在,一个char数组最少消耗4G,我们还可以最少,即开比特位,比如一个字节开8个比特位,我们也可以开int的,如下图,0到7映射到第一个cha人,8到15映射到第二个char,依次映射,40亿个数,如果是一个整数去存储需要16G,现在是按位去存储,用位去标识,缩小了32倍,也可以这么说,这是40亿个整数看成40亿个比特位,除以8大概就是相当于5亿字节,需要512MB,这里东西就叫位图
位图:它是一种直接定址法的哈希映射,用来判断整型的在不在的问题,用每一位来存放某种状态,适用于海量数据,数据无重复的场景。
在这里插入图片描述

(2)简单模拟实现


	template<size_t N>
	class bitset
	{
	public:
		bitset()
		{
			_b.resize(N / 8 + 1, 0);
		}
		void set(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;
			_b[i] |= (1 << j);

		}
		void reset(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;
			_b[i] &= ~(1 << j);
		}
		bool test(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;
			return _b[i] & (1 << j);
		}
	private:
		vector<char> _b;

	};

库里面这个函数是有的,我们是不能去按位去开数组的,我们可以用vector数组存储char类型控制char。
我们需要实现里面三个核心接口set和set以及test,set把x映射的那个比特位设置成1,reset把它设置成0,test判断在不在。
初始化构造:我们还需要空间,我们要N个比特位我们需要开N/8,但这样少开一个比特位需要加上1,然后初始都为0。
先实现set
但是我们怎么去找到对应的比特位?
1、一个字节是8比特位,我们是算它在第几个8比特位,我们可以直接除8算出i即在第i个char数组位置,接着算在第几个8比特第几个上面,可以直接模8算出j即char位置第几个比特位。
2、然后我们把char的第j位设置为1,我们需要进行位运算,我们需要把j位设置成1,其他位不能影响需要用到或,因为或有一个特点0和任何数或还是任何数,我们还需用1进行左移j位,左移是向高位移,最后再或等,这样设置完毕。如下图
在这里插入图片描述

实现reset
同样先算出i和j,想让它第j位设置为0,先左移再取反,但是不能那个影响其它位,就需要按位与等,因为1和1与还是1,0和1与还是0。
实现判断test
同样先算出i和j,对对应的位置直接与,两种可能性,与之后除了第j位其他位都为0,如果第j位是0,那么结果就是0返回假,如果第j为不是0,那么结果是非0
值,非0值即为真不管是1还是其他非0数,都返回真。注意位运算优先级是很低的需要加括号。
我们测试一下:
在这里插入图片描述
那么开头那个问题就可以解决。

(3)位图应用

我们再看几个问题:
2.给100亿个整数,设计算法只出现一次的整数。
部分核心代码

template<size_t N>
	class twobitset
	{
	public:
		void set(size_t x)
		{
			if (_b1.test(x) == false && _b2.test(x) == false)
			{
				_b2.set(x);
			}
			else if (_b1.test(x) == false && _b2.test(x) == true)
			{
				_b1.set(x);
				_b2.reset(x);
			}
		}
		void one_print()
		{
			for (size_t i = 0; i < N; ++i)
			{
				if(_b2.test(i))
				{
				     cout << i << endl;
                }
			}
		}
	public:
		bitset<N> _b1;
		bitset<N> _b2;
	};

100亿个整数不影响我们开空间,因为可能有重复的,我们可以搞2个位图。出现0次就是00,出现1就是01次,出现1次以上就是10。
直接运用刚才的两个位图,直接复用,两个位进行组合。
_b1和_b2都test一下如果都是00表示没有出现过,就把_b2设置成1即01表示出现了1次,如果是_b1为0,_b2为1就把_b1设置为为,_b2设置为0即10表示出现2次。
接着写个打印函数去找出现1次,N是个范围,只需要遍历,只需要判断_b2是真,就是出现1次,因为01,打印即可
如图:
在这里插入图片描述

3.给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?
第一种:可以把其中一个文件的值,读到内存的一个位图中,再读取另一个文件,判断在不在上面位图中,在就是交集。但是找出的交集存在重复的值,还要再次去重。可以改进,每次找到交集,都将上面的位图对应的值设置为0解决重复问题。
第二种:更好的是放到两个位图中,把文件1放到位图1,把文件2放到位图2。
读取文件1的数据映射到位图1,读取文件2的数据映射到位图2,用for循环遍历范围N,如果位图1和位图2都在就是交集。
如果数据量大就选第二种方法,反之第一种。
在这里插入图片描述

4.位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数。
这道类似第二道,用第二道题的思想,出现0次用00表示,出现1用01表示,出现2次用10表示,出现3次以上用11表示。不超过2次的所有整数就去找01和10。

总结:位图也是一种哈希结构,效率很高速度快,O(1),而且还节省内存。
缺点就是:只能映射整型,统计次数也有限。其他类型string,double等不能映射。下面的布隆过滤器就是解决这种问题。

二、布隆过滤器

(1)关于布隆过滤器概念及介绍

如果是大量字符串,位图是没法完成映射的,如果用哈希或红黑树,会有大量消耗,有附带消耗。我们可以用仿函数转成整型,间接映射,但是这样会有一个冲突问题,假如字符串是汉字,字符串的长度是8,会有256^8中组合,会存在多对一冲突。
而布隆过滤器的思想不是解决冲突,而是降低冲突概率,一个值映射一个位置容易误判,映射多个位置就可以降低误判率,即将一个元素用多个哈希函数映射到一个位图中,因此被映射到的位置的比特位一定为1。所以可以按照以下方式进行查找,分别计算每个哈希值对应的比特位置存储的是否为零,只要有一个为零,代表该元素一定不在哈希表中,否则可能在哈希表中。

(2)布隆过滤器的使用场景

首先要找到它的特点,它能容忍误判的场景,比如我们在注册时,快速判断昵称是否使用过。如果没注册过,会立刻给你反馈,说明是准确的;如果它注册过有两种可能性,把昵称放到这个布隆中,第一它真的被用过了,第二它没被用过,存在了误判,但是从用户使用场景上是不知道的,可以允许误判,昵称用户感知不到。
如果是昵称,10亿个用户是存在数据库里面的,数据库的数据本质在磁盘上,快速不判断是不去找磁盘的,因为磁盘IO太慢了,所以我们把昵称全部读到布隆过滤器里面,节省空间,在布隆就直接反馈昵称注册过,不在布隆就反馈没注册过,但是在是会存在误判的,有可能真没被注册过。
如果是手机号,判断不在就直接返回没注册过,不在是准确的,判断在,可能会存在误判,明明没有注册过,这时候要去数据库里面磁盘上确认一下,然后再返回这个结果,以数据库的结果为准。这个跟直接去数据库查找相比,从整体而言效率是高的。因为布隆是在内存当中时间复杂度是O(1),把不在的都快速过滤掉,如果在的话再去找数据库,单拿在的场景多消耗了一点,整而言效率高,减少了数据库的访问。
布隆过滤器为啥叫这个名字,它是先提前做一层过滤,不在就直接走了,在的话再去数据库确认一下再返回。它的优点是快节省内存,缺点存在误判。
如下图:
在这里插入图片描述
大部分使用布隆过滤器的数据类型都是用字符串,如果用整型就用位图。

减少磁盘IO和网络请求,一旦一个值必定不存在,就不用进行后面的查询。BF实践当中一般都是做数据过滤,判断在不在,如果不在就不用再往后请求了,如果在继续再往后面请求,如果再次请求数据都在数据库里面,甚至数据库在远程服务器中,还要走一层网络,成本还是蛮高的。

(3)模拟实现

主要先上部分核心代码,后面有原码。

template<size_t N,class K=string,class Hash1= BKDRHash,
		class Hash2= APHash,class Hash3= DJBHash>
	class BloomFilter
	{
	public:
		void set(const K& key)
		{
			size_t len = N * _M;
			size_t hash1 = Hash1()(key) % len;
			_b.set(hash1);
			size_t hash2 = Hash2()(key) % len;
			_b.set(hash2);
			size_t hash3 = Hash3()(key) % len;
			_b.set(hash3);
		}
		bool test(const K& key)
		{
			size_t len = N * _M;
			size_t hash1 = Hash1()(key) % len;
			if (!_b.test(hash1))
				return false;

			size_t hash2 = Hash2()(key) % len;
			if (!_b.test(hash2))
				return false;

			size_t hash3= Hash3()(key) % len;

			if (!_b.test(hash3))
				return false;

			return true;
		}
	private:
		static const size_t _M = 6;
		bitset<N*_M> _b;
	};

我们在模板里面增加三个hash函数算法,可以在网上搜字符串哈希函数算法,我所取的这个三个hash函数的散列质量及效率是别人进过测试后排在前三的。在set函数里面先给一个哈希映射的第一个位置,把key转成可以去摸的整型值,摸上N,同理3个hash函数,set3个位置。
如果判断在不在,三个位置都要在才在即真,只有一个位置不在就是不在即假。
有一个关键问题:在和不在谁会存在误判?
在是不准确的,会存在误判,如果判断一个位置不在,说明至少有一个位置为0,上面说到只要有一个不在就是不在;如果判断在的话,这个位置不可能为0,三个位置都为1。比如一个字符串,本来不在,但是它映射的位置都跟别人冲突了即都被被人映射了,所以导致认为它在,即误判。

hash函数个数,代表一个值映射几个位,哈希函数越多,误判率越低,但是希函数越多,平均空间越多。
这是下面别人通过实验总结出来的公式,来降低误判率,此图链接来源于:链接。
在这里插入图片描述

以上的测试结果可以看出布隆过滤器的长度会直接影响误报率,布隆过滤器越长其误报率越小。哈希函数的个数也需要考虑,但治不了本。因为n插入个数和BF长度存在一个倍数,我们适当增加倍数_M,来验证一下,6是最好的。如图:
在这里插入图片描述
找的是不在的字符串去测试,因为本来就在测试时它肯定在,它不在的有可能能会被判断成在,这就是误判,结果是在是不准确的,因为本来不在它会判断成在。

(4)布隆过滤器天生不支持删除reset

因为会对别人造成影响以及其他影响(即使用计数法(由多个比特位控制)也非常不好,不确定删除哪个数据以及本来不在误判成在的数据,把它删了其他的又找不到了),如下图,删除nza,会把2号位置置成0,再查找azn,查找时就不在了,有关联影响。
在这里插入图片描述

(5)BF总结

布隆过滤器优点
1.增加和查询元素的时间复杂度为:O(K), (K为哈希函数的个数,一般比较小),与数据量大小无

2. 哈希函数相互之间没有关系,方便硬件并行运算
3. 布隆过滤器不需要存储元素本身,在某些对保密要求比较严格的场合有很大优势
4. 在能够承受一定的误判时,布隆过滤器比其他数据结构有这很大的空间优势
5. 数据量很大时,布隆过滤器可以表示全集,其他数据结构不能
6. 使用同一组散列函数的布隆过滤器可以进行交、并、差运算
布隆过滤器缺陷
1.有误判率,即存在假阳性(False Position),即不能准确判断元素是否在集合中(补救方法:再
建立一个白名单,存储可能会误判的数据)
2.不能获取元素本身
3.一般情况下不能从布隆过滤器中删除元素
4.如果采用计数方式删除,可能会存在计数回绕问题

三、海量数据处理

(1) 哈希切割

(1)问题1/2

1.给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法
这里是找交集,不是整型的是字符串。
近似算法:就是之前说的,先把一个文件的数据放到BF中,再去找交集判断在不在,在就是交集,当然后面还有去重的需求。
精确算法:query本质就是一个字符串,假设单个query平均50字节,100亿个就是500G。我们可以如下图把文件A和B文件分别切成1000份(linux指令就可以切,写一个进程帮我们执行切文件的指令。),这样做还是要和每个文件找交集,所以我们可以用hash切分,用一个哈希函数计算出每个文件对应的i即文件号,然后让A0和B0,A1和B1依次找交集,只需要编号相同的小文件直接去找交集,因为一个一个的小文件就像一个桶,进入同一个桶都是冲突的值,A和B相同字符串会进去编号的相同小文件,而且我们用的是相同hash函数。
在这里插入图片描述

但是会有一个问题
某些小文件不是平均切分,可能会出现冲突过多,某个Ai,Bi小文件过大,太大加载不去内存,如果换个哈希函数再切,前提还是要算出这个两个文件多大,才决定你要切多少份,更重要的问题是继续换哈希函数可能切不动,因为有大量重复,而且这里还有两种可能:
第一种可能单个文件有大量重复的query字符串
第二种可能有大量不同的query。
第一种重复的值不管用什么哈希函数都切不动,第二种大量不同的字符串肯定可以继续用哈希函数切分,主要是怎么区分,要分别处理,
解决
我们可以这样直接使用一个unordered_set/set,依次读取文件query,插入set中
如果读取整个小文件query,都可以成功插入,那就是第一种,因为set插入key,如果有了返回false,没有继续插返回true,插入过程是不会失败的。
如果读取整个小文件query,插入过程抛异常,说明内存满了装不下,会抛bad_alloc异常,那就是第二种,要换其他哈希函数,再次分割,再求交集。

2.如何扩展BloomFilter使得它支持删除元素的操作
把每个映射的值改成引用计数,每个值由多个比特位组成,如01,10,11,分别代表1次,2次。3次,往上加,取决于用几个比特位。但其实没必要,会浪费空间,本身就不支持删除。

(2)问题3/4

3.给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址?
还是一样的,哈希切分500份,依次读取数据,Hash函数计算出i,这个ip就是第i个小文件,直接用unordered_map/map统计出现次数。
如果某个过程中,出现抛异常,则说明单个文件小文件过大,冲突太多,需要重新换哈希函数,再次哈希切分这个小文件,比如这个单个小文件10G再切个30份,AA0到AA29,再生成小文件,和处理源文件的逻辑是一样的;没有异常正常统计,统计完一个小文件,记录最大的,clear,再统计下一个文件。

(3)问题3

4.与上题条件相同,如何找到top K的IP?
找次数最多IP,可以建一个K个数的小堆,小堆每一个位置是pair,key是ip,value是次数,如果比你大我就进去。
总结:相同的IP一定进入相同小文件,读取单个小文件,就可以统计IP出现次数。

四、所有源码(含BF)

bitset.h

#pragma once
#include<vector>
#include<string>
#include<iostream>
#include<ctime>
using namespace std;

namespace nza
{
	template<size_t N>
	class bitset
	{
	public:
		bitset()
		{
			_b.resize(N / 8 + 1, 0);
		}
		void set(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;
			_b[i] |= (1 << j);

		}
		void reset(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;
			_b[i] &= ~(1 << j);
		}
		bool test(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;
			return _b[i] & (1 << j);
		}
	private:
		vector<char> _b;

	};


	void test1()
	{
		bitset<100> bs;
		bs.set(6);
		bs.set(15);
		bs.set(66);
		cout << bs.test(6) << endl;
		cout << bs.test(7) << endl;
		cout << bs.test(66) << endl;
		cout << endl;
	}



	template<size_t N>
	class twobitset
	{
	public:
		void set(size_t x)
		{
			if (_b1.test(x) == false && _b2.test(x) == false)
			{
				_b2.set(x);
			}
			else if (_b1.test(x) == false && _b2.test(x) == true)
			{
				_b1.set(x);
				_b2.reset(x);
			}
		}
		void one_print()
		{
			for (size_t i = 0; i < N; ++i)
			{
				if(_b2.test(i))
				{
				     cout << i << endl;
                }
			}
		}
	public:
		bitset<N> _b1;
		bitset<N> _b2;
	};

	void test2()
	{
		int a[] = { 6, 22, 99, 88, 6, 4, 3, 22, 5,};
		twobitset<100> tb;
		for (auto e : a)
		{
			tb.set(e);
		}
		tb.one_print();
		cout << endl;
	}
	






	struct BKDRHash
	{
		size_t operator()(const string& s)
		{
			size_t hash = 0;
			for (auto ch : s)
			{
				hash += ch;
				hash *= 31;
			}

			return hash;
		}
	};

	struct APHash
	{
		size_t operator()(const string& s)
		{
			size_t hash = 0;
			for (long i = 0; i < s.size(); i++)
			{
				size_t ch = s[i];
				if ((i & 1) == 0)
				{
					hash ^= ((hash << 7) ^ ch ^ (hash >> 3));
				}
				else
				{
					hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));
				}
			}
			return hash;
		}
	};


	struct DJBHash
	{
		size_t operator()(const string& s)
		{
			size_t hash = 5381;
			for (auto ch : s)
			{
				hash += (hash << 5) + ch;
			}
			return hash;
		}
	};

	template<size_t N,class K=string,class Hash1= BKDRHash,
		class Hash2= APHash,class Hash3= DJBHash>
	class BloomFilter
	{
	public:
		void set(const K& key)
		{
			size_t len = N * _M;
			size_t hash1 = Hash1()(key) % len;
			_b.set(hash1);
			size_t hash2 = Hash2()(key) % len;
			_b.set(hash2);
			size_t hash3 = Hash3()(key) % len;
			_b.set(hash3);
		}
		bool test(const K& key)
		{
			size_t len = N * _M;
			size_t hash1 = Hash1()(key) % len;
			if (!_b.test(hash1))
				return false;

			size_t hash2 = Hash2()(key) % len;
			if (!_b.test(hash2))
				return false;

			size_t hash3= Hash3()(key) % len;

			if (!_b.test(hash3))
				return false;

			return true;
		}
	private:
		static const size_t _M = 6;
		bitset<N*_M> _b;
	};


	void test_BF1()
	{
		BloomFilter<100> b;
		b.set("nza");
		b.set("zan");
		b.set("qwe");
		b.set("ewq");


		cout << b.test("nza") << endl;
		cout << b.test("zan") << endl;
		cout << b.test("qwe") << endl;
		cout << b.test("ewq") << endl;
		cout << b.test("kd") << endl;
	}
	void test_BF2()
	{
		srand(time(0));
		const size_t N = 10000;
		BloomFilter<N> bf;

		std::vector<std::string> v1;
		std::string url = "https://www.education.com/-kd/2023/06/12/66666.html";

		for (size_t i = 0; i < N; ++i)
		{
			v1.push_back(url + std::to_string(i));
		}

		for (auto& str : v1)
		{
			bf.set(str);
		}
		std::vector<std::string> v2;
		for (size_t i = 0; i < N; ++i)
		{
			std::string url = "https://www.education.com/-kd/2023/06/12/66666.html";
			url += std::to_string(999999 + i);
			v2.push_back(url);
		}

		size_t n2 = 0;
		for (auto& str : v2)
		{
			if (bf.test(str))
			{
				++n2;
			}
		}
		cout << "相似字符串误判率:" << (double)n2 / (double)N << endl;

	
		

		std::vector<std::string> v3;
		for (size_t i = 0; i < N; ++i)
		{
			string url = "https://editor.csdn.net/md?articleId=131012473";
			url += std::to_string(i + rand());
			v3.push_back(url);
		}

		size_t n3 = 0;
		for (auto& str : v3)
		{
			if (bf.test(str))
			{
				++n3;
			}
		}
		cout << "不相似字符串误判率:" << (double)n3 / (double)N << endl;
	}
}

test.cpp

#include"bitset.h"

int main()
{
	nza::test1();
	nza::test2();
	nza::test_BF1();
	nza::test_BF2();
	return 0;
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/32470.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【前端布局篇】浮动、定位、弹性布局,固比固、双飞翼、圣杯布局

一、布局方式介绍 布局模型是基于盒模型基础上进行的拓展&#xff0c;关于布局有流式布局&#xff08;标准的布局&#xff09;&#xff0c;浮动布局、定位布局、flex布局等。 1.1 标准流&#xff08;流动模型&#xff09; 描述&#xff1a;元素按照自己默认的元素类型在页面…

Unity3D 连接MySQL数据库

1、MySQL下载安装运行 详见&#xff1a;MySQL下载安装运行 2、使用mysql-connector-net &#xff08;1&#xff09;官方下载地址&#xff1a;https://downloads.mysql.com/archives/c-net/&#xff0c;下载后直接双击安装即可。 提示&#xff1a;不要使用版本过高的connect…

Jmeter(三) - 从入门到精通 - 测试计划(Test Plan)的元件(详解教程)

1.简介 上一篇中我已经教你如何通过JMeter来创建一个测试计划&#xff08;Test Plan&#xff09;&#xff0c;那么这一篇我们就将JMeter启动起来&#xff0c;创建一个测试计划&#xff08;Test plan&#xff09;&#xff0c;然后现在给大家介绍一下测试计划&#xff08;Test P…

C# wpf 附加属性实现任意控件拖动调整大小

摘自这里 https://blog.csdn.net/u013113678/article/details/121719278 调试效果如下 using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using Syst…

【信号】信号处理与进程通信:快速上手

目录 0. 信号概述 1. 产生信号的方式&#xff1a; 1.1 当用户按某些终端键时&#xff0c;将产生信号。 1.2 硬件异常将产生信号。 1.3 软件异常将产生信号。 1.4 调用kill函数将发送信号。 1.5 运行kill命令将发送信号。 2. 信号的默认&#xff08;缺省&#xff09;处理…

Visual C++类的继承及类中成员的访问特性——搞懂public、protected、private

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天来说说Visual C中类的继承及类中成员的访问特性&#xff0c;也就是来搞懂public、protected、private这三个东西。 很多人搞不清楚这三个东西&#xff0c;并且很容易弄错&#xff0c;其实不是学习的人的…

ModaHub魔搭社区:向量数据库MIlvus服务端配置(三)

目录 gpu 区域 logs 区域 metric_config 区域 gpu 区域 在该区域选择是否在 Milvus 里启用 GPU 用于搜索和索引创建。同时使用 CPU 和 GPU 可以达到资源的最优利用&#xff0c;在特别大的数据集里做搜索时性能更佳。 若要切换到 CPU-only 模式&#xff0c;只要将 enable 设…

【VMD-LSTM】变分模态分解-长短时记忆神经网络研究(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

数据库大题

(计算题&#xff0c;20分) 设有两个关系R和S,求① R ∪ S R \cup S R∪S;② R − S R - S R−S;③ R S R \times S RS;④ ∏ C , A ( R ) \prod_{C,A}(R) ∏C,A​(R);⑤ σ B > ′ 4 ′ ( R ) \sigma_{B>4}(R) σB>′4′​(R) 关系R关系S (简答题&#xff0c;10…

基于深度学习FasterRCNN模型Restnet50 的生活垃圾智能分类(准确率达84%)-含python工程全源码

目录 前言总体设计系统整体结构图系统流程图 运行环境1. 硬件环境2. Python 环境 模块实现1. 数据预处理2. 数据加载3. 模型构建4. 模型训练及保存5. 模型加载与调用 系统测试1. 模型准确率2. 分类别准确率 工程源代码下载其它资料下载 前言 本项目基于Faster R-CNN模型&#…

jenkins流水线Pipeline的使用

pipeline流水线 1、jenkins安装pipeline插件 2、创建流水线项目 1、创建pipeline的流水线项目 2、编写流水线 pipeline {agent anystages {stage(拉去代码) {steps {git credentialsId: gitee, url: https://gitee.com/xwb1056481167/jenkins-demo.gitecho 拉去代码}}stage(m…

Vue中如何进行数据导入与Excel导入

Vue中如何进行数据导入与Excel导入 Vue是一款非常流行的JavaScript框架&#xff0c;它提供了一套用于构建用户界面的工具和库。在Vue中&#xff0c;我们可以使用多种方式来导入数据&#xff0c;包括从服务器获取数据、从本地存储获取数据、从文件中读取数据等等。其中&#xf…

NVIDIA Jetson TX1,TX2,TX2 NX,AGX Xavier 和 Nano开发板GPIO口配置及应用

NVIDIA Jetson TX1&#xff0c;TX2&#xff0c;TX2 NX&#xff0c;AGX Xavier 和 Nano开发板GPIO口配置及应用 简介 ​ Jetson TX1、TX2、TX2 NX、AGX Xavier和Nano开发板都配备了一个包含40个引脚的GPIO接头&#xff0c;这些引脚可以用于数字输入输出。如下图 ​ 类似于Rasp…

Solid Converter PDF v10 安装及使用教程

目录 一、软件介绍二、下载教程三、安装教程四、使用教程1.PDF转Word、Html等2.合并PDF文件 一、软件介绍 Solid Converter PDF是一套专门将PDF文件转换成Word的软件。 能够将PDF转换为Word、Excel、HTML、PowerPoint、纯文本文件从PDF文档中提取数据并以CSV等格式保存能够转…

【人工智能】— 深度神经网络、卷积神经网络(CNN)、多卷积核、全连接、池化

【人工智能】— 深度神经网络、卷积神经网络&#xff08;CNN&#xff09;、多卷积核、全连接、池化 深度神经网络训练训练深度神经网络参数共享 卷积神经网络&#xff08;CNN&#xff09;卷积多卷积核卷积全连接最大池化卷积池化拉平向量激活函数优化小结 深度神经网络训练 Pr…

Pytest+selenium+allure+Jenkins自动化测试框架搭建及使用

一、 环境搭建 1. Python下载及安装 Python可应用于多平台包括windows, Linux 和 Mac OS X, 本文主要介绍windows环境下。你可以通过终端窗口输入 "python" 命令来查看本地是否已经安装Python以及Python的安装版本。 如未安装python, 推荐下载python 3.8.3以…

Prompt的技巧持续总结

Prompt 有很多网站已经收录了&#xff0c;比如&#xff1a;aimappro 有些直接抄上述网站的作业即可&#xff0c;不过也来看看&#xff0c; 有一些日常提问大概的咒语该怎么写。 1 三种微调下的提示写法 chatgpt时代的创新&#xff1a;LLM的应用模式比较 实际案例说明AI时代大…

将win上的文件传输到Ubuntu虚拟机

首先获取Ubuntu系统的ip地址&#xff0c;在Ubuntu的Terminal中输入ifconfig&#xff0c;可以看到Ubuntu的ip地址 可以看到我电脑的ip地址是10.0.2.15。更改虚拟机的网络连接 这里以VirtualBox为例&#xff0c;打开VirtualBox设置&#xff0c;选择网络&#xff0c;将连接方式改…

通付盾入围《2023年度中国数字安全能力图谱(行业版)》

近日&#xff0c;数世咨询发布《2023年度中国数字安全能力图谱&#xff08;行业版&#xff09;》。通付盾作为以分布式数字身份和大数据决策智能技术为核心的数字化高端软件与服务提供商&#xff0c;凭借在数字安全领域的实力和影响力&#xff0c;入选政府、互联网两大行业细分…

ElasticSearch的安装和访问

ElasticSearch的安装 前言: 本次下载是在Windows系统进行操作,版本为7.6.1,因为下周最新版本的8.1.2有问题 ElasticSearch基于Java开发,JDK最低1.8版本 ElasticSearch的版本要和之后引入的Maven的Jar包版本对应 1 下载ElasticSearch 官网:https://www.elastic.co/cn/ 产品…