Rumah > Tutorial CMS > WordTekan > Terokai kuasa Penapis Bloom menggunakan Node.js dan Redis

Terokai kuasa Penapis Bloom menggunakan Node.js dan Redis

PHPz
Lepaskan: 2023-09-01 22:53:09
asal
1073 orang telah melayarinya

使用 Node.js 和 Redis 探索 Bloom Filter 的魅力

Dalam kes penggunaan yang betul, penapis mekar kelihatan seperti sihir. Itu pernyataan yang berani, tetapi dalam tutorial ini kita akan meneroka struktur data yang aneh ini, cara terbaik untuk menggunakannya, dan beberapa contoh praktikal menggunakan Redis dan Node.js.

Penapis Bloom ialah struktur data sehala yang berkemungkinan. Perkataan "penapis" boleh mengelirukan dalam konteks ini menapis bermaksud ia adalah perkara yang aktif, kata kerja, tetapi mungkin lebih mudah untuk menganggapnya sebagai simpanan, kata nama. Dengan penapis bunga mudah anda boleh melakukan dua perkara:

  1. Tambah item.
  2. Periksa sama ada item belum ditambah sebelum ini.
Ini adalah had penting untuk difahami - anda tidak boleh memadamkan item, anda juga tidak boleh menyenaraikan item dalam penapis bloom. Selain itu, anda tidak boleh menentukan sama ada item telah ditambahkan pada penapis pada masa lalu. Di sinilah sifat kebarangkalian penapis Bloom memainkan peranan - positif palsu adalah mungkin, tetapi positif palsu tidak. Jika penapis disediakan dengan betul, kemungkinan positif palsu adalah sangat kecil.

Varian penapis bloom wujud yang menambahkan fungsi tambahan seperti pemadaman atau penskalaan, tetapi ia juga menambahkan kerumitan dan pengehadan. Sebelum beralih kepada variasi, adalah penting untuk memahami penapis bunga yang mudah dahulu. Artikel ini hanya memperkenalkan penapis Bloom mudah.

Dengan had ini, anda mendapat banyak faedah: saiz tetap, penyulitan berasaskan cincang dan carian pantas.

Apabila anda menyediakan penapis bloom, anda perlu menentukan saiz untuknya. Saiz ini adalah tetap, jadi jika terdapat satu atau bilion item dalam penapis, ia tidak akan membesar melebihi saiz yang ditentukan. Apabila anda menambahkan lebih banyak item pada penapis, kemungkinan positif palsu meningkat. Jika anda menentukan penapis yang lebih kecil, kadar positif palsu akan meningkat lebih cepat berbanding jika anda menggunakan penapis yang lebih besar.

Penapis Bloom dibina berdasarkan konsep pencincangan sehala. Sama seperti menyimpan kata laluan dengan betul, penapis Bloom menggunakan algoritma pencincangan untuk menentukan pengecam unik item yang dihantar ke dalamnya. Hash pada asasnya tidak boleh diterbalikkan dan diwakili oleh rentetan aksara yang kelihatan rawak. Oleh itu, jika seseorang mendapat akses kepada penapis mekar, ia tidak akan mendedahkan apa-apa secara langsung.

Akhir sekali, penapis mekar adalah pantas. Operasi ini melibatkan perbandingan yang jauh lebih sedikit daripada kaedah lain dan boleh disimpan dengan mudah dalam ingatan, menghalang hits pangkalan data yang memberi kesan prestasi.

Sekarang anda memahami batasan dan kelebihan penapis Bloom, mari lihat beberapa situasi di mana ia boleh digunakan.

Tetapan

Kami akan menggambarkan penapis Bloom menggunakan Redis dan Node.js. Redis ialah medium storan untuk penapis Bloom ia pantas, dalam memori dan mempunyai beberapa arahan khusus (GETBIT, SETBIT) , yang boleh meningkatkan kecekapan pelaksanaan. Saya menganggap anda telah memasang Node.js, npm dan Redis pada sistem anda. Pelayan Redis anda harus berjalan pada port lalai pada localhost agar contoh kami berfungsi dengan baik.

GETBITSETBIT),可以提高实施效率。我假设您的系统上安装了 Node.js、npm 和 Redis。您的 Redis 服务器应该在 localhost 上的默认端口上运行,以便我们的示例正常工作。

在本教程中,我们不会从头开始实现过滤器;而是从头开始实现过滤器。相反,我们将重点关注 npm 中预构建模块的实际用途:bloom-redis。 bloom-redis 有一组非常简洁的方法:addcontainsclear

如前所述,布隆过滤器需要哈希算法来生成项目的唯一标识符。 bloom-redis 使用众所周知的 MD5 算法,尽管它可能不适合 Bloom 过滤器(有点慢,有点过大),但可以正常工作。

独特的用户名

用户名,尤其是在 URL 中标识用户的用户名,需要是唯一的。如果您构建一个允许用户更改用户名的应用程序,那么您可能需要一个从未使用过的用户名,以避免用户名混淆和被攻击。

如果没有布隆过滤器,您需要引用一个包含曾经使用过的每个用户名的表,而大规模时这可能会非常昂贵。布隆过滤器允许您在用户每次采用新名称时添加一个项目。当用户检查用户名是否被占用时,您所需要做的就是检查布隆过滤器。它将能够绝对确定地告诉您所请求的用户名是否先前已添加。过滤器可能会错误地返回用户名已被使用,而实际上用户名尚未被使用,但这只是为了谨慎起见,不会造成任何真正的伤害(除了用户可能无法声明“k3w1d00d47”) .

为了说明这一点,让我们使用 Express 构建一个快速的 REST 服务器。首先,创建 package.json 文件,然后运行以下终端命令。

npm 安装bloom-redis --save

npm install express --save

npm install redis --saveDalam tutorial ini, kami tidak akan melaksanakan penapis dari awal; Sebaliknya, kami akan menumpukan pada penggunaan praktikal modul pra-bina dalam npm: bloom-redis. bloom-redis mempunyai set kaedah yang sangat ringkas: add, contains dan clear kod >.

🎜Seperti yang dinyatakan sebelum ini, penapis Bloom memerlukan algoritma pencincangan untuk menjana pengecam unik item. bloom-redis menggunakan algoritma MD5 yang terkenal, yang berfungsi dengan baik walaupun ia mungkin tidak sesuai untuk penapis Bloom (agak perlahan, agak berlebihan). 🎜 🎜Nama pengguna unik🎜 🎜Nama pengguna, terutamanya yang mengenal pasti pengguna dalam URL, perlu unik. Jika anda membina aplikasi yang membenarkan pengguna menukar nama pengguna mereka, anda mungkin mahu nama pengguna yang tidak pernah digunakan untuk mengelakkan kekeliruan dan serangan nama pengguna. 🎜 🎜Tanpa penapis bloom, anda perlu merujuk jadual yang mengandungi setiap nama pengguna yang pernah digunakan, yang boleh menjadi sangat mahal pada skala. Penapis Bloom membolehkan anda menambah item setiap kali pengguna menggunakan nama baharu. Apabila pengguna menyemak untuk melihat sama ada nama pengguna telah diambil, semua yang anda perlu lakukan ialah menyemak penapis bloom. Ia akan dapat memberitahu anda dengan pasti sama ada nama pengguna yang diminta telah ditambahkan sebelum ini. Penapis mungkin tersilap mengembalikan bahawa nama pengguna telah diambil sedangkan sebenarnya nama pengguna belum diambil, tetapi ini hanyalah langkah berjaga-jaga dan tidak menyebabkan sebarang bahaya sebenar (selain daripada itu pengguna mungkin tidak dapat mengisytiharkan "k3w1d00d47") .🎜 🎜Untuk menggambarkan perkara ini, mari bina pelayan REST pantas menggunakan Express. Mula-mula, buat fail package.json dan jalankan perintah terminal berikut. 🎜 🎜npm pasang bloom-redis --save🎜 🎜npm install express --save🎜 🎜npm pasang redis --save🎜Saiz pilihan lalai

bloom-redis ditetapkan kepada 2 MB. Itu salah kerana berhati-hati, tetapi ia agak besar. Menetapkan saiz penapis mekar adalah penting: terlalu besar dan anda membazir memori, terlalu kecil dan kadar positif palsu akan menjadi terlalu tinggi. Matematik yang terlibat dalam menentukan saiz adalah kompleks dan di luar skop tutorial ini, tetapi nasib baik terdapat kalkulator saiz penapis mekar yang melakukan kerja tanpa perlu memecahkan buku teks.

Sekarang, buat app.js seperti berikut: app.js 如下:

var
  Bloom         =   require('bloom-redis'),
  express       =   require('express'),
  redis         =   require('redis'),
  
  app,
  client,
  filter;

//setup our Express server
app = express();

//create the connection to Redis
client = redis.createClient();


filter = new Bloom.BloomFilter({ 
  client    : client, //make sure the Bloom module uses our newly created connection to Redis
  key       : 'username-bloom-filter', //the Redis key
  
  //calculated size of the Bloom filter.
  //This is where your size / probability trade-offs are made
  //http://hur.st/bloomfilter?n=100000&p=1.0E-6
  size      : 2875518, // ~350kb
  numHashes : 20
});

app.get('/check', function(req,res,next) {
  //check to make sure the query string has 'username'
  if (typeof req.query.username === 'undefined') {
    //skip this route, go to the next one - will result in a 404 / not found
    next('route');
  } else {
   filter.contains(
     req.query.username, // the username from the query string
     function(err, result) {
       if (err) { 
        next(err); //if an error is encountered, send it to the client
        } else {
          res.send({ 
            username : req.query.username, 
            //if the result is false, then we know the item has *not* been used
            //if the result is true, then we can assume that the item has been used
            status : result ? 'used' : 'free' 
          });
        }
      }
    );
  }
});


app.get('/save',function(req,res,next) {
  if (typeof req.query.username === 'undefined') {
    next('route');
  } else {
    //first, we need to make sure that it's not yet in the filter
    filter.contains(req.query.username, function(err, result) {
      if (err) { next(err); } else {
        if (result) {
          //true result means it already exists, so tell the user
          res.send({ username : req.query.username, status : 'not-created' });
        } else {
          //we'll add the username passed in the query string to the filter
          filter.add(
            req.query.username, 
            function(err) {
              //The callback arguments to `add` provides no useful information, so we'll just check to make sure that no error was passed
              if (err) { next(err); } else {
                res.send({ 
                  username : req.query.username, status : 'created' 
                });
              }
            }
          );
        }
      }
    });
  }
});

app.listen(8010);
Salin selepas log masuk

要运行此服务器:node app.js。转到浏览器并将其指向:https://localhost:8010/check?username=kyle。响应应该是:{"username":"kyle","status":"free"}

现在,让我们通过将浏览器指向 http://localhost:8010/save?username=kyle 来保存该用户名。响应将是:{"username":"kyle","status":"created"}。如果返回地址 http://localhost:8010/check?username=kyle,响应将是 {"username":"kyle","status ":"已使用"}.同样,返回 http://localhost:8010/save?username=kyle 将导致 {"username":"kyle","status":"not -创建“}

从终端中,您可以看到过滤器的大小: redis-cli strlen 用户名-bloom-filter

现在,对于一项,它应该显示 338622

现在,继续尝试使用 /save 路由添加更多用户名。您想尝试多少就尝试多少。

如果您再次检查尺寸,您可能会发现尺寸略有增加,但并非每次添加都会增加。很好奇,对吧?在内部,布隆过滤器在保存在 username-bloom 的字符串中的不同位置设置各个位(1/0)。然而,这些并不是连续的,因此如果您在索引 0 处设置一位,然后在索引 10,000 处设置一位,则两者之间的所有内容都将为 0。对于实际用途,一开始了解每个操作的精确机制并不重要,只需知道这一点即可这是正常的,您在 Redis 中的存储永远不会超过您指定的值。

新鲜内容

网站上的新鲜内容可以吸引用户回头客,那么如何每次都向用户展示新的内容呢?使用传统的数据库方法,您可以向表中添加一个包含用户标识符和故事标识符的新行,然后在决定显示一段内容时查询该表。正如您可能想象的那样,您的数据库将增长得非常快,尤其是随着用户和内容的增长。

在这种情况下,漏报(例如不显示看不见的内容)的后果非常小,这使得布隆过滤器成为一个可行的选择。乍一看,您可能认为每个用户都需要一个布隆过滤器,但我们将使用用户标识符和内容标识符的简单串联,然后将该字符串插入到我们的过滤器中。这样我们就可以对所有用户使用单个过滤器。

在此示例中,让我们构建另一个显示内容的基本 Express 服务器。每次您访问路由 /show-content/any-usernameany-username 是任何 URL 安全值)时,都会显示一条新内容,直到该网站没有内容。在示例中,内容是古腾堡计划前十名书籍的第一行。

我们需要再安装一个 npm 模块。从终端运行: npm install async --save

var
  async         =   require('async'),
  Bloom         =   require('bloom-redis'),
  express       =   require('express'),
  redis         =   require('redis'),
  
  app,
  client,
  filter,
  
  // From Project Gutenberg - opening lines of the top 10 public domain ebooks
  // https://www.gutenberg.org/browse/scores/top
  openingLines = {
    'pride-and-prejudice' : 
      'It is a truth universally acknowledged, that a single man in possession of a good fortune, must be in want of a wife.',
    'alices-adventures-in-wonderland' : 
      'Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do: once or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it' }
      
Salin selepas log masuk

Untuk menjalankan pelayan ini: node app.js. Pergi ke penyemak imbas anda dan arahkannya ke: https://localhost:8010/check?username=kyle. Jawapannya hendaklah: {"username":"kyle","status":"free"}.

Sekarang, mari simpan nama pengguna itu dengan menghalakan penyemak imbas anda ke http://localhost:8010/save?username=kyle. Jawapannya ialah: {"username":"kyle","status":"created"}. Jika alamat pemulangan ialah http://localhost:8010/check?username=kyle, jawapannya ialah {"username":"kyle "," status ":"Used"}. Begitu juga, mengembalikan http://localhost:8010/save?username=kyle akan menghasilkan {"username":"kyle","status":"not -created"}.

Dari terminal anda boleh melihat saiz penapis: redis-cli strlen username-bloom-filter.

Sekarang, untuk satu item, ia sepatutnya tertera 338622.

Sekarang, teruskan dan cuba tambah lebih banyak nama pengguna menggunakan laluan /save. Anda boleh mencuba seberapa banyak yang anda mahu.

Jika anda menyemak saiz sekali lagi, anda mungkin mendapati saiznya telah meningkat sedikit, tetapi tidak dengan setiap penambahan. Penasaran kan? Secara dalaman, penapis bloom menetapkan bit individu (1/0) di lokasi berbeza dalam rentetan yang disimpan dalam nama pengguna-bloom. Walau bagaimanapun, ini tidak bersebelahan, jadi jika anda menetapkan sedikit pada indeks 0 dan kemudian menetapkan sedikit pada indeks 10,000, segala-galanya di antaranya akan menjadi 0. Untuk tujuan praktikal, tidak penting untuk memahami mekanik yang tepat bagi setiap operasi pada mulanya, cuma ketahui bahawa ini adalah perkara biasa dan anda tidak akan menyimpan lebih banyak dalam Redis daripada yang anda tentukan. 🎜 🎜Kandungan segar🎜 🎜Kandungan segar di laman web boleh menarik pengguna untuk kembali, jadi bagaimana untuk menunjukkan kandungan baharu kepada pengguna setiap masa? Menggunakan pendekatan pangkalan data tradisional, anda akan menambah baris baharu pada jadual yang mengandungi pengecam pengguna dan pengecam cerita, dan kemudian menanyakan jadual apabila anda memutuskan untuk memaparkan sekeping kandungan. Seperti yang anda bayangkan, pangkalan data anda akan berkembang dengan sangat cepat, terutamanya apabila pengguna dan kandungan anda berkembang. 🎜 🎜Dalam kes ini, akibat negatif palsu (mis. tidak menunjukkan kandungan ghaib) adalah sangat kecil, menjadikan penapis bloom sebagai pilihan yang berdaya maju. Pada pandangan pertama, anda mungkin berfikir bahawa setiap pengguna memerlukan penapis Bloom, tetapi kami akan menggunakan gabungan mudah pengecam pengguna dan pengecam kandungan, dan kemudian memasukkan rentetan itu ke dalam penapis kami. Dengan cara ini kita boleh menggunakan penapis tunggal untuk semua pengguna. 🎜 🎜Dalam contoh ini, mari bina pelayan Express asas lain yang memaparkan kandungan. Setiap kali anda mengakses laluan /show-content/any-username (any-username ialah sebarang nilai selamat URL), sekeping kandungan baharu akan dipaparkan sehingga tapak tidak mempunyai kandungan. Dalam contoh, kandungannya ialah baris pertama daripada sepuluh buku Project Gutenberg teratas. 🎜 🎜Kita perlu memasang modul npm yang lain. Jalankan dari terminal: npm install async --save🎜 🎜Fail app.js baharu anda: 🎜
var
  async           =   require('async'),
  Bloom           =   require('bloom-redis'),
  bodyParser      =   require('body-parser'),
  express         =   require('express'),
  redis           =   require('redis'),
  
  app,
  client,
  filter,
  
  currentDataKey  = 'current-data',
  usedDataKey     = 'used-data';
  
app = express();
client = redis.createClient();

filter = new Bloom.BloomFilter({ 
  client    : client,
  key       : 'stale-bloom-filter',
  //for illustration purposes, this is a super small filter. It should fill up at around 500 items, so for a production load, you'd need something much larger!
  size      : 1024,
  numHashes : 20
});

app.post(
  '/',
  bodyParser.text(),
  function(req,res,next) {
    var
      used;
      
    console.log('POST -', req.body); //log the current data being posted
    console.time('post'); //start measuring the time it takes to complete our filter and conditional verification process
    
    //async.series is used to manage multiple asynchronous function calls.
    async.series([
      function(cb) {
        filter.contains(req.body, function(err,filterStatus) {
          if (err) { cb(err); } else {
            used = filterStatus;
            cb(err);
          }
        });
      },
      function(cb) {
        if (used === false) {
          //Bloom filters do not have false negatives, so we need no further verification
          cb(null);
        } else {
          //it *may* be in the filter, so we need to do a follow up check
          //for the purposes of the tutorial, we'll add a 150ms delay in here since Redis can be fast enough to make it difficult to measure and the delay will simulate a slow database or API call
          setTimeout(function() {
            console.log('possible false positive');
            client.sismember(usedDataKey, req.body, function(err, membership) {
              if (err) { cb(err); } else {
                //sismember returns 0 if an member is not part of the set and 1 if it is.
                //This transforms those results into booleans for consistent logic comparison
                used = membership === 0 ? false : true;
                cb(err);
              }
            });
          }, 150);
        }
      },
      function(cb) {
        if (used === false) {
          console.log('Adding to filter');
          filter.add(req.body,cb);
        } else {
          console.log('Skipped filter addition, [false] positive');
          cb(null);
        }
      },
      function(cb) {
        if (used === false) {
          client.multi()
            .set(currentDataKey,req.body) //unused data is set for easy access to the 'current-data' key
            .sadd(usedDataKey,req.body) //and added to a set for easy verification later
            .exec(cb); 
        } else {
          cb(null);
        }
      }
      ],
      function(err, cb) {
        if (err) { next(err); } else {
          console.timeEnd('post'); //logs the amount of time since the console.time call above
          res.send({ saved : !used }); //returns if the item was saved, true for fresh data, false for stale data.
        }
      }
    );
});

app.get('/',function(req,res,next) {
  //just return the fresh data
  client.get(currentDataKey, function(err,data) {
    if (err) { next(err); } else {
      res.send(data);
    }
  });
});

app.listen(8012);
Salin selepas log masuk
Salin selepas log masuk
🎜Jika anda memberi perhatian yang teliti kepada masa perjalanan pergi dan balik dalam alatan pembangunan, anda akan mendapati bahawa semakin banyak kali anda meminta laluan tunggal dengan nama pengguna, semakin lama masa yang diperlukan. Semasa menyemak penapis mengambil masa yang tetap, dalam kes ini kami sedang menyemak kehadiran lebih banyak item. Penapis Bloom terhad dalam perkara yang mereka boleh beritahu anda, jadi anda sedang menguji kehadiran setiap item. Sudah tentu, dalam contoh kami ia agak mudah, tetapi menguji beratus-ratus projek adalah tidak cekap. 🎜 🎜Data lapuk🎜 🎜Dalam contoh ini, kami akan membina pelayan Express kecil yang akan melakukan dua perkara: menerima data baharu melalui POST dan memaparkan data semasa (menggunakan permintaan GET). Apabila data baharu diposkan ke pelayan, aplikasi menyemak sama ada ia wujud dalam penapis. Jika ia tidak wujud, kami akan menambahkannya pada koleksi dalam Redis, jika tidak, kami akan mengembalikannya nol. Permintaan GET akan mendapatkannya daripada Redis dan menghantarnya kepada pelanggan. 🎜 🎜Ini berbeza daripada dua kes pertama, positif palsu tidak boleh diterima. Kami akan menggunakan penapis bloom sebagai barisan pertahanan pertama. Memandangkan sifat penapis bloom, kami hanya boleh memastikan ada sesuatu yang tiada dalam penapis, jadi dalam kes ini kami boleh terus membiarkan data masuk. Jika penapis bloom mengembalikan data yang mungkin ada dalam penapis, kami menyemak dengan sumber data sebenar. 🎜

那么,我们得到了什么?我们获得了不必每次都检查实际来源的速度。在数据源速度较慢的情况下(外部 API、小型数据库、平面文件的中间),确实需要提高速度。为了演示速度,我们在示例中添加 150 毫秒的实际延迟。我们还将使用 console.time / console.timeEnd 来记录 Bloom 过滤器检查和非 Bloom 过滤器检查之间的差异。

在此示例中,我们还将使用极其有限的位数:仅 1024。它很快就会填满。当它填满时,它将显示越来越多的误报 - 您会看到响应时间随着误报率的填满而增加。

该服务器使用与之前相同的模块,因此将 app.js 文件设置为:

var
  async           =   require('async'),
  Bloom           =   require('bloom-redis'),
  bodyParser      =   require('body-parser'),
  express         =   require('express'),
  redis           =   require('redis'),
  
  app,
  client,
  filter,
  
  currentDataKey  = 'current-data',
  usedDataKey     = 'used-data';
  
app = express();
client = redis.createClient();

filter = new Bloom.BloomFilter({ 
  client    : client,
  key       : 'stale-bloom-filter',
  //for illustration purposes, this is a super small filter. It should fill up at around 500 items, so for a production load, you'd need something much larger!
  size      : 1024,
  numHashes : 20
});

app.post(
  '/',
  bodyParser.text(),
  function(req,res,next) {
    var
      used;
      
    console.log('POST -', req.body); //log the current data being posted
    console.time('post'); //start measuring the time it takes to complete our filter and conditional verification process
    
    //async.series is used to manage multiple asynchronous function calls.
    async.series([
      function(cb) {
        filter.contains(req.body, function(err,filterStatus) {
          if (err) { cb(err); } else {
            used = filterStatus;
            cb(err);
          }
        });
      },
      function(cb) {
        if (used === false) {
          //Bloom filters do not have false negatives, so we need no further verification
          cb(null);
        } else {
          //it *may* be in the filter, so we need to do a follow up check
          //for the purposes of the tutorial, we'll add a 150ms delay in here since Redis can be fast enough to make it difficult to measure and the delay will simulate a slow database or API call
          setTimeout(function() {
            console.log('possible false positive');
            client.sismember(usedDataKey, req.body, function(err, membership) {
              if (err) { cb(err); } else {
                //sismember returns 0 if an member is not part of the set and 1 if it is.
                //This transforms those results into booleans for consistent logic comparison
                used = membership === 0 ? false : true;
                cb(err);
              }
            });
          }, 150);
        }
      },
      function(cb) {
        if (used === false) {
          console.log('Adding to filter');
          filter.add(req.body,cb);
        } else {
          console.log('Skipped filter addition, [false] positive');
          cb(null);
        }
      },
      function(cb) {
        if (used === false) {
          client.multi()
            .set(currentDataKey,req.body) //unused data is set for easy access to the 'current-data' key
            .sadd(usedDataKey,req.body) //and added to a set for easy verification later
            .exec(cb); 
        } else {
          cb(null);
        }
      }
      ],
      function(err, cb) {
        if (err) { next(err); } else {
          console.timeEnd('post'); //logs the amount of time since the console.time call above
          res.send({ saved : !used }); //returns if the item was saved, true for fresh data, false for stale data.
        }
      }
    );
});

app.get('/',function(req,res,next) {
  //just return the fresh data
  client.get(currentDataKey, function(err,data) {
    if (err) { next(err); } else {
      res.send(data);
    }
  });
});

app.listen(8012);
Salin selepas log masuk
Salin selepas log masuk

由于使用浏览器 POST 到服务器可能会很棘手,所以让我们使用curl 来测试。

curl --data“您的数据放在这里”--header“内容类型:text/plain”http://localhost:8012/

可以使用快速 bash 脚本来显示填充整个过滤器的外观:

#!/bin/bash
for i in `seq 1 500`;
do
  curl --data “data $i" --header "Content-Type: text/plain" http://localhost:8012/
done   
Salin selepas log masuk

观察填充或完整的过滤器很有趣。由于这个很小,你可以使用 redis-cli 轻松查看。通过在添加项目之间从终端运行 redis-cli get stale-filter ,您将看到各个字节增加。完整的过滤器将为每个字节 \xff 。此时,过滤器将始终返回正值。

结论

布隆过滤器并不是万能的解决方案,但在适当的情况下,布隆过滤器可以为其他数据结构提供快速、有效的补充。

如果您仔细注意开发工具中的往返时间,您会发现使用用户名请求单个路径的次数越多,所需的时间就越长。虽然检查过滤器需要固定的时间,但在本例中,我们正在检查是否存在更多项目。布隆过滤器能够告诉您的信息有限,因此您正在测试每个项目是否存在。当然,在我们的示例中,它相当简单,但测试数百个项目效率很低。

Atas ialah kandungan terperinci Terokai kuasa Penapis Bloom menggunakan Node.js dan Redis. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan