key/data pair与索引文件

本文探讨了Swish2.6版本中采用BerkeleyDB进行索引存储的优化方案,对比了hash表和key-data pair两种存储方式,并介绍了其在桌面搜索应用中的实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-font-kerning:1.0pt;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} -->

前段时间浏览 swish 2.6 版本的代码,其中的索引存储采用了 Berkeley DB ,直接通过 key data pair 方式进行存储( Berkeley DB 本身就是轻量级的,通过 key-data pair 进行数据的存储)。

Swish 2.6 中对于 ENTRY 词条的存储基于 key/data pair 方法。词条的 word 作为 key ,位置信息等作为 data ,通过数据库的方式进行存储。

 

例如:对于词条 china ,出现在 filenum1 的标题中和 filenum2 中的文章内容中。此时,可以将词条作为 key ,位置等信息作为 data ,数据设计为:

<metaID><datasize>< 所在文件 ><position><metaID><datasize>< 所在文件 ><position>

其中, metaID 相当与 lucene 中的 field 域。

在查询的时候,通过 key china )获得 data ,直接分析其中的位置信息即可。但是 key/pair 存储仅支持完全匹配查询。(当然,可以增加一个查询处理层,对于通配符查询等进行处理)。

swish2.4 原先的索引文件设计中,将词条 ENTRY 通过 hash 方法映射到 hash 表中,然后直接按照 binary file 的方式写入文件。应该说,效率方面比不了 key/pair 访问方式。

 

打算在桌面搜索的程序中,用 kerkeley DB 进行处理。

template<class T> struct HashBucketNode { T _data; HashBucketNode<T>* _next; HashBucketNode(const T& data) :_data(data) ,_next(nullptr) {} }; // K 为 T 中key的类型 // T 可能是键值对,也可能是K // KeyOfT: 从T中提取key // Hash将key转化为整形,因为哈市函数使用除留余数法 template<class K, class T, class KeyOfT, class Hash> class HashBucket { template<class K, class V, class HF> friend class unordered_map; typedef HashBucketNode<T> Node; typedef HBIterator<K, T, KeyOfT, Hash> Iterator; typedef HBIterator<K, const T, KeyOfT, Hash> const_Iterator; public: HashBucket() { _tables.resize(10, nullptr); } Iterator begin() { for (size_t i = 0; i < _tables.size(); i++) { Node* cur = _tables[i]; if (cur) return { cur,*this }; } return { nullptr,*this }; } Iterator end() { return { nullptr,*this }; } size_t size() { return _n; } bool emptr() { return _n; } // 哈希桶的销毁 ~HashBucket() { for (size_t i = 0; i < _tables.size(); i++) { Node* cur = _tables[i]; while (cur) { Node* next = cur->_next; delete cur; cur = next; } } } /********************************************************************/ /********************************************************************/ unsigned long __stl_next_prime(unsigned long n) { // Note: assumes long is at least 32 bits. static const int __stl_num_primes = 28; static const unsigned long __stl_prime_list[__stl_num_primes] = { 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741, 3221225473, 4294967291 }; const unsigned long* first = __stl_prime_list; const unsigned long* last = __stl_prime_list + __stl_num_primes; const unsigned long* pos = lower_bound(first, last, n); return pos == last ? *(last - 1) : *pos; } /********************************************************************/ // 插入值为data的元素,如果data存在则不插入 pair<iterator, bool> Insert(const T& data) { KeyOfT kot; Hash hash; Iterator it = Find(kot(data)); if (it._pHt) return { it., *this }; if (_n == _tables.size()) { vector<Node*> newTables(__stl_next_prime(_tables.size() + 1), nullptr); for (size_t i = 0; i < _tables.size(); i++) { Node* cur = _tables[cur]; while (cur) { Node* next = cur->_next; size_t hashi = hash(kot(cur->_data)) % newTables.size(); cur->_next = newTables[hashi]; newTables[hashi] = cur; cur = next; } _tables[hashi] = nullptr; } _tables.swap(newTables); } size_t hashi = hash(kot(data)) % _tables.size(); Node* newnode = new Node(data); newnode->_next = _tables[hashi]; _tables[hashi] = newnode; ++_n; return { iterator{ newnode,*this }, ture }; } // 在哈希桶中查找值为key的元素,存在返回true否则返回false iterator Find(const K& key) { KeyOfT kot; Hash hash; size_t hashi = hash(key) % _tables.size(); Node* cur = _tables[hashi]; while (cur) { if (kot(cur->_data) == key) { return { cur,*this }; } cur = cur->_next; } return { nullptr,*this }; } // 哈希桶中删除key的元素,删除成功返回true,否则返回false bool Erase(const K& key) { KeyOfT kot; Hash hash; size_t hashi = hash(key) % _tables.size(); Node* cur = _tables[hashi]; Node* prev = nullptr; while (cur) { if (kot(cur->_data) == key) { if (prev == nullptr) { _tables[hashi] = nullptr; } else { prev->_next = cur->_next; delete cur; --_n; return true; } } prev = cur; cur = cur->_next; } return false; } Iterator Erase(Iterator position) { KeyOfT kot; Iterator it = Find(kot(position.)) if() } private: vector<Node*> _tables; // 指针数组 size_t _n = 0; // 表中存储数据个数 };编写下面namespace bit { // 为了实现简单,在哈希桶的迭代器类中需要用到hashBucket本身, template<class K, class V, class KeyOfValue, class HF> class HashBucket; // 注意:因为哈希桶在底层是单链表结构,所以哈希桶的迭代器不需要--操作 template <class K, class V, class KeyOfValue, class HF> struct HBIterator { typedef HashBucket<K, V, KeyOfValue, HF> HashBucket; typedef HashBucketNode<V>* PNode; typedef HBIterator<K, V, KeyOfValue, HF> Self; HBIterator(PNode pNode = nullptr, HashBucket* pHt = nullptr); Self& operator++() { // 当前迭代器所指节点后还有节点时直接取其下一个节点 if (_pNode->_pNext) _pNode = _pNode->_pNext; else { // 找下一个不空的桶,返回该桶中第一个节点 size_t bucketNo = _pHt->HashFunc(KeyOfValue()(_pNode->_data))+1; for (; bucketNo < _pHt->BucketCount(); ++bucketNo) { if (_pNode = _pHt->_ht[bucketNo]) break; } } return *this; } Self operator++(int); V& operator*(); V* operator->(); bool operator==(const Self& it) const; bool operator!=(const Self& it) const; PNode _pNode; // 当前迭代器关联的节点 HashBucket* _pHt; // 哈希桶--主要是为了找下一个空桶时候方便 }; // unordered_map中存储的是pair<K, V>的键值对,K为key的类型,V为value的类型,HF哈希函数类型 // unordered_map在实现时,只需将hashbucket中的接口重新封装即可 template<class K, class V, class HF = DefHashF<K>> class unordered_map { typedef HashBucket<K, pair<K, V>, KeyOfValue, HF> HT; // 通过key获取value的操作 struct KeyOfValue { const K& operator()(const pair<K, V>& data) { return data.first;} }; public: typename typedef HT::Iterator iterator; public: unordered_map(): _ht() {} //////////////////////////////////////////////////// iterator begin(){ return _ht.begin();} iterator end(){ return _ht.end();} //////////////////////////////////////////////////////////// // capacity size_t size()const{ return _ht.size();} bool empty()const{return _ht.empty();} /////////////////////////////////////////////////////////// // Acess V& operator[](const K& key) { pair<iterator, bool> ret = _ht.InsertUnique(pair<K, V>(key, V())); return ret.fisrt->second; } const V& operator[](const K& key)const; ////////////////////////////////////////////////////////// // lookup iterator find(const K& key){ return _ht.Find(key);} size_t count(const K& key){ return _ht.Count(key);} ///////////////////////////////////////////////// // modify pair<iterator, bool> insert(const pair<K, V>& valye) { return _ht.Insert(valye);} iterator erase(iterator position) { return _ht.Erase(position);} //////////////////////////////////////////////////////////// // bucket size_t bucket_count(){ return _ht.BucketCount();} size_t bucket_size(const K& key){ return _ht.BucketSize(key);} private: HT _ht; }; }
07-10
#pragma once #include <iostream> #include <utility> #include <assert.h> #include <vector> using namespace std; namespace bit { template<class K> struct HashFunc { size_t operator()(const K& key) { return (size_t)key; } }; // 为了实现简单,在哈希桶的迭代器类中需要用到hashBucket本身, template<class K, class V, class KeyOfValue, class Hash> class HashBucket; template<class T> class HashBucketNode; // 注意:因为哈希桶在底层是单链表结构,所以哈希桶的迭代器不需要--操作 template <class K, class V, class KeyOfValue, class Hash = HashFunc<K>> struct HBIterator { typedef HashBucket<K, V, KeyOfValue, Hash> HashBucket; typedef HashBucketNode<V>* PNode; typedef HBIterator<K, V, KeyOfValue, Hash> Self; HBIterator(PNode pNode = nullptr, HashBucket* pHt = nullptr) :_pNode(PNode) ,_pHt(pHt) {} HBIterator(const HBIterator<K, V, KeyOfValue, Hash>& it) { *_pHt = *(it._pHt); _pNode = it._pNode; } Self& operator++() { // 当前迭代器所指节点后还有节点时直接取其下一个节点 if (_pNode->_pNext) _pNode = _pNode->_pNext; else { // 找下一个不空的桶,返回该桶中第一个节点 size_t bucketNo = _pHt->HashFunc(KeyOfValue()(_pNode->_data)) + 1; for (; bucketNo < _pHt->BucketCount(); ++bucketNo) { _pNode = _pHt->_ht[bucketNo]; if (_pNode) break; } if (bucketNo == _pHt->BucketCount()) _pNode = nullptr; } return *this; } Self operator++(int) { Self temp = *this; ++(*this); return temp; } V& operator*() { KeyOfValue kot; return _pNode->_data; } V* operator->() { return &_pNode->_data; } bool operator==(const Self& it) const { return _pNode == it._pNode; } bool operator!=(const Self& it) const { return _pNode != it._pNode; } PNode _pNode; // 当前迭代器关联的节点 HashBucket* _pHt; // 哈希桶--主要是为了找下一个空桶时候方便 }; // unordered_map中存储的是pair<K, V>的键值对,K为key的类型,V为value的类型,HF哈希函数类型 // unordered_map在实现时,只需将hashbucket中的接口重新封装即可 template<class K, class V, class HF = DefHashF<K>> class unordered_map { typedef HashBucket<K, pair<K, V>, KeyOfValue, HF> HT; // 通过key获取value的操作 struct KeyOfValue { const K& operator()(const pair<K, V>& data) { return data.first; } }; public: typename typedef HT::Iterator iterator; public: unordered_map() : _ht() {} //////////////////////////////////////////////////// iterator begin() { return _ht.begin(); } iterator end() { return _ht.end(); } //////////////////////////////////////////////////////////// // capacity size_t size()const { return _ht.size(); } bool empty()const { return _ht.empty(); } /////////////////////////////////////////////////////////// // Acess V& operator[](const K& key) { pair<iterator, bool> ret = _ht.InsertUnique(pair<K, V>(key, V())); return ret.fisrt->second; } const V& operator[](const K& key)const; ////////////////////////////////////////////////////////// // lookup iterator find(const K& key) { return _ht.Find(key); } size_t count(const K& key) { return _ht.Count(key); } ///////////////////////////////////////////////// // modify pair<iterator, bool> insert(const pair<K, V>& valye) { return _ht.Insert(valye); } iterator erase(iterator position) { return _ht.Erase(position); } //////////////////////////////////////////////////////////// // bucket size_t bucket_count() { return _ht.BucketCount(); } size_t bucket_size(const K& key) { return _ht.BucketSize(key); } private: HT _ht; }; template<class T> struct HashBucketNode { T _data; HashBucketNode<T>* _next; HashBucketNode(const T& data) :_data(data) , _next(nullptr) {} }; template<class K, class T, class KeyOfT, class Hash> class HashBucket { typedef HashBucketNode<T> Node; typedef HashBucket<K, T, KeyOfT, Hash> Self; public: template<class K> struct HashFunc { size_t operator()(const K& key) { return (size_t)key; } }; unsigned long __stl_next_prime(unsigned long n) { // Note: assumes long is at least 32 bits. static const int __stl_num_primes = 28; static const unsigned long __stl_prime_list[__stl_num_primes] = { 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741, 3221225473, 4294967291 }; const unsigned long* first = __stl_prime_list; const unsigned long* last = __stl_prime_list + __stl_num_primes; const unsigned long* pos = lower_bound(first, last, n); return pos == last ? *(last - 1) : *pos; } HashBucket() { _tables.resize(__stl_next_prime(_tables.size()), nullptr); } HashBucket(const Self& ht) { _tables = new Node(ht._tables.size(), nullptr); _n = ht._n; for (size_t i = 0; i < _tables.size(); i++) { Node* cur = ht._tables[i]; Node* prev = nullptr; while (cur) { Node* newnode = new Node(cur->_data); if (prev == nullptr) { _tables[i] = newnode; } else { prev->_next = newnode; } prev = cur; cur = cur->_next; } } } Self& operator=(const Self& ht) { _tables.resize(ht._tables.size(), nullptr); _n = ht._n; for (size_t i = 0; i < _tables.size(); i++) { Node* cur = ht._tables[i]; Node* prev = nullptr; while (cur) { Node* newnode = new Node(cur->_data); if (prev == nullptr) { _tables[i] = newnode; } else { prev->_next = newnode; } prev = cur; cur = cur->_next; } } } // 哈希桶的销毁 ~HashBucket() { for (auto& e : _tables) { Node* cur = e; Node* next = nullptr; while (cur) { next = cur->_next; delete cur; cur = next; } } } // 插入值为data的元素,如果data存在则不插入 bool Insert(const T& data) { KeyOfT kot; Hash hash; if (_n == _tables.size()) { HashTable<K, T, KeyOfT, Hash> newTable(__stl_next_prime(_n + 1), nullptr); for (auto& e : _tables) { Node* cur = e; size_t i = 0; while (cur) { Node* next = cur->_next; size_t hashi = hash(kot(cur->_data)) % newTable.size(); cur->_next = newTable[hashi]; newTable[hashi] = cur; cur = next; } _tables[i++] = nullptr; } _tables.swap(newTable); } size_t hashi = hash(kot(data)) % _tables.size(); Node* newnode = new Node(data); newnode->_next = _tables[hashi]; _tables[hashi] = newnode; _n++; return true; } // 在哈希桶中查找值为key的元素,存在返回true否则返回false bool Find(const K& key) { KeyOfT kot; Hash hash; size_t hashi = hash(key) % _tables.size(); Node* cur = _tables[hashi]; while (cur) { if (kot(cur->_data) == key) return true; cur = cur->_next; } return false; } // 哈希桶中删除key的元素,删除成功返回true,否则返回false bool Erase(const K& key) { KeyOfT kot; Hash hash; size_t hashi = hash(key) % _tables.size(); Node* prev = nullptr; Node* cur = _tables[hashi]; while (cur) { if (kot(cur->_data) == key) { if (prev == nullptr) { _tables[hashi] = cur->_next; delete cur; } else { prev->_next = cur->_next; delete cur; } --_n; return true; } prev = cur; } return false; } private: vector<Node*> _tables; // 指针数组 size_t _n = 0; // 表中存储数据个数 }; }
07-10
Cmdline: com.sisheng.aiaio pid: 26403, tid: 26516, name: pool-8-thread-1 >>> com.sisheng.aiaio <<< #01 pc 0000000000706a78 /data/app/~~3OsD3qqIcdh8cap-LK-yPw==/com.sisheng.aiaio-dUsHkeVrEjOwSinRUyVR3g==/base.apk!librknnrt.so (offset 0x494f000) (BuildId: 37b1e9d4e376e328c6ea301178644cfd452cdfa7) #02 pc 0000000000706ca0 /data/app/~~3OsD3qqIcdh8cap-LK-yPw==/com.sisheng.aiaio-dUsHkeVrEjOwSinRUyVR3g==/base.apk!librknnrt.so (offset 0x494f000) (BuildId: 37b1e9d4e376e328c6ea301178644cfd452cdfa7) #03 pc 0000000000706b30 /data/app/~~3OsD3qqIcdh8cap-LK-yPw==/com.sisheng.aiaio-dUsHkeVrEjOwSinRUyVR3g==/base.apk!librknnrt.so (offset 0x494f000) (BuildId: 37b1e9d4e376e328c6ea301178644cfd452cdfa7) #04 pc 00000000007060d4 /data/app/~~3OsD3qqIcdh8cap-LK-yPw==/com.sisheng.aiaio-dUsHkeVrEjOwSinRUyVR3g==/base.apk!librknnrt.so (offset 0x494f000) (BuildId: 37b1e9d4e376e328c6ea301178644cfd452cdfa7) #05 pc 0000000000706028 /data/app/~~3OsD3qqIcdh8cap-LK-yPw==/com.sisheng.aiaio-dUsHkeVrEjOwSinRUyVR3g==/base.apk!librknnrt.so (offset 0x494f000) (__cxa_throw+124) (BuildId: 37b1e9d4e376e328c6ea301178644cfd452cdfa7) #06 pc 00000000000abd5c /data/app/~~3OsD3qqIcdh8cap-LK-yPw==/com.sisheng.aiaio-dUsHkeVrEjOwSinRUyVR3g==/base.apk!libyolov8pose.so (offset 0xa2f7000) (BuildId: a8240c032d1fdb26dfbae932cd6df7bfaf91793f) #07 pc 00000000000a1f10 /data/app/~~3OsD3qqIcdh8cap-LK-yPw==/com.sisheng.aiaio-dUsHkeVrEjOwSinRUyVR3g==/base.apk!libyolov8pose.so (offset 0xa2f7000) (std::__ndk1::unordered_map<int, std::__ndk1::array<int, 2ul>, std::__ndk1::hash<int>, std::__ndk1::equal_to<int>, std::__ndk1::allocator<std::__ndk1::pair<int const, std::__ndk1::array<int, 2ul> > > >::at(int const&)+96) (BuildId: a8240c032d1fdb26dfbae932cd6df7bfaf91793f) #08 pc 00000000000a1cdc /data/app/~~3OsD3qqIcdh8cap-LK-yPw==/com.sisheng.aiaio-dUsHkeVrEjOwSinRUyVR3g==/base.apk!libyolov8pose.so (offset 0xa2f7000) (Java_com_sisheng_fitscreen_pose_Yolov8Pose_getRtspFrame+72) (BuildId: a8240c032d1fdb26dfbae932cd6df7bfaf91又出现这个了
03-15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值