I denne artikel opbygger vi en streamingliste med tweets baseret på en søgeforespørgsel, som brugeren har indtastet. Tweetsene vil blive hentet ved hjælp af Twitters Streaming API, gemt i en Redis-liste og opdateret i front-end ved hjælp af Socket.io. Vi vil primært bruge Redis som et cachinglag til at hente tweets.
Introduktion
Her er en kort beskrivelse af de teknologier, vi vil bruge:
Redis
Redis er et open source (BSD-licenseret), datastrukturlager i hukommelsen, der bruges som database, cache og meddelelsesmægler. Det understøtter datastrukturer såsom strenge, hashes, lister, sæt, sorterede sæt med områdeforespørgsler, bitmaps, hyperloglogs og geospatiale indekser med radiusforespørgsler.
Node.js
Node.js er en platform bygget på Chromes JavaScript-runtime for nemt at bygge hurtige og skalerbare netværksapplikationer. Node.js bruger en begivenhedsdrevet, ikke-blokerende I/O-model, der gør den let og effektiv og dermed perfekt til dataintensive realtidsapplikationer, der kører på tværs af distribuerede enheder.
Express.js
Express.js er en Node.js-ramme. Du kan oprette server- og serversidekoden til en applikation ligesom de fleste andre websprog, men ved at bruge JavaScript.
Socket.IO
Socket.IO er et JavaScript-bibliotek til webapplikationer i realtid. Det muliggør tovejskommunikation i realtid mellem webklienter og servere. Det har to dele:et klientsidebibliotek, der kører på browseren, og et serversidebibliotek til Node.js. Begge komponenter har næsten identiske API'er.
Heroku
Heroku er en cloud-platform, der lader virksomheder bygge, levere, overvåge og skalere apps – det er den hurtigste måde at gå fra idé til URL-adresse og omgå al den infrastruktur-hovedpine.
Denne artikel antager, at du allerede har Redis, Node.js og Heroku Toolbelt installeret på din maskine.
Opsætning
- Download koden fra følgende lager: https://github.com/Scalegrid/code-samples/tree/sg-redis-node-socket-twitter-search/node-socket-redis-twitter-hashtags
- Kør npm install for at installere de nødvendige komponenter
- Endelig kan du starte nodeserveren ved at lave "node index.js". Du kan også køre "nodemon", som også holder øje med filændringer.
Du kan også få adgang til en hostet version af denne app her: https://node-socket-redis-stream-tweet.herokuapp.com/
Processen
Her er en kort beskrivelse af processen, som vi vil bruge til at bygge demoapplikationen:
1. Vi starter med at acceptere en søgeforespørgsel fra brugeren. Forespørgslen kan være Twitter-omtaler, hashtags eller enhver tilfældig søgetekst.
2. Når vi har søgeforespørgslen, sender vi den til Twitters Streaming API for at hente tweets. Da det er en stream, vil vi lytte, når tweets sendes af API'et.
3. Så snart et tweet er hentet, gemmer vi det på en Redis-liste og udsender det til front-end.
Hvad er Redis-lister?
Redis-lister implementeres via linkede lister. Det betyder, at selvom du har millioner af elementer inde på en liste, udføres operationen med at tilføje et nyt element ved hovedet eller siden af listen konstant. Hastigheden for at tilføje et nyt element med LPUSH-kommandoen til toppen af en liste med ti elementer er den samme som at tilføje et element til hovedet på en liste med 10 millioner elementer.
I vores applikation vil vi gemme de tweets, der modtages via API'et, på en liste kaldet "tweets". Vi vil bruge LPUSH til at skubbe det nyligt modtagne tweet til listen, trimme det ved hjælp af LTRIM, som begrænser mængden af brugt diskplads (da skrivning af en stream kan tage meget plads), hente det seneste tweet ved hjælp af LRANGE og udsende det til frontenden, hvor den vil blive tilføjet til streaminglisten.
Hvad er LPUSH, LTRIM og LRANGE?
Disse er et sæt Redis-kommandoer, der bruges til at tilføje data til en liste. Her er en kort beskrivelse:
LPUSH
Indsæt alle de angivne værdier i toppen af listen gemt ved tasten. Hvis nøglen ikke findes, oprettes den som en tom liste, før push-handlingerne udføres. Når nøglen indeholder en værdi, der ikke er en liste, returneres en fejl.
redis> LPUSH mylist "world"(heltal) 1redis> LPUSH mylist "hello"(heltal) 2redis> LRANGE mylist 0 -11) "hello"2) "world"
LTRIM
Trim en eksisterende liste, så den kun vil indeholde det specificerede udvalg af elementer. Både start og stop er nul-baserede indekser, hvor 0 er det første element på listen (hovedet), 1 det næste element og så videre.
redis> RPUSH mylist "one"(heltal) 1redis> RPUSH mylist "to"(heltal) 2redis> RPUSH mylist "tre"(heltal) 3redis> LTRIM mylist 1 -1"OK"redis> LRANGE mylist 0 -11 ) "to"2) "tre"
LRANGE
Returnerer de angivne elementer i listen gemt ved nøgle. Forskydningens start og stop er nul-baserede indekser, hvor 0 er det første element på listen (listens hoved), 1 er det næste, og så videre.
Disse forskydninger kan også være negative tal, der angiver positioner fra slutningen af listen. For eksempel er -1 det sidste element på listen, -2 det næstsidste og så videre.
redis> RPUSH mylist "one"(heltal) 1redis> RPUSH mylist "to"(heltal) 2redis> RPUSH mylist "tre"(heltal) 3redis> LRANGE mylist 0 01) "one"redis> LRANGE mylist -3 21 ) "en"2) "to"3) "tre"
Opbygning af applikationen
Vores demo kræver både en front-end og en back-end. Vores front-end er et ret simpelt tekstfelt med en knap, der vil blive brugt til at starte streamen.
$('body').on('click', '.btn-search', function() { $('#tweets_area').empty(); $(this).text('Streaming.. .').attr('disabled', true); $.ajax({ url:'/search', type:'POST', data:{ val:$.trim($('.search-txt'). val()) } });});
Vi har brug for en hjælpefunktion til at bygge en tweet-boks, når vi modtager tweetet fra vores back-end:
var _buildTweetBox =function(status) { var html =''; html +=''; html +=''; $('#tweets_area').prepend(html); $('#tweets_area').find('.tweet-single').first().fadeIn('slow');};'; html +=' '; html +=' '; html +=' '; html +=''; html +=''; html +=''; html +='' + status.user.screen_name + '
'; html +='' + status.text + '
'; html +='
Vi har også brug for en lytter til at stoppe streamen og forhindre at tilføje flere tweets til streaminglisten:
socket.on('stream:destroy', function(status) { $('.btn-search').text('Start streaming').removeAttr('disabled'); $('.alert-warning ').fadeIn('slow'); setTimeout(function() { $('.alert-warning').fadeOut('slow'); }, STREAM_END_TIMEOUT * 1000);});
Lad os skifte til bagsiden af tingene og begynde at skrive vores /search API.
/** * API - Søg */app.post('/search', function(req, res, next) { _searchTwitter(req.body.val); res.send({ status:'OK' } );});/** * Stream data fra Twitter til inputtekst * * 1. Brug Twitter streaming API til at spore en specifik værdi indtastet af brugeren * 2. Når vi har dataene fra Twitter, skal du tilføje dem til en Redis liste ved hjælp af LPUSH * 3. Efter tilføjelse til listen, begræns listen ved hjælp af LTRIM, så streamen ikke flyder over disken * 4. Brug LRANGE til at hente det seneste tweet og udsende det til front-end ved hjælp af Socket.io * * @ param {String} val Query String * @return */var _searchTwitter =function(val) { twit.stream('statuses/filter', {track:val}, function(stream) { stream.on('data', function (data) { client.lpush('tweets', JSON.stringify(data), function() { client.ltrim('tweets', 0, TWEETS_TO_KEEP, function() { client.lrange('tweets', 0, 1 , function(err, tweetListStr) { io.emit('savedTweetToRedis', JSON.parse(tweetListStr[0])); }); }); }); }); stream.on('destroy', function(response) {io.emit('stream:destroy'); }); stream.on('end', function(response) { io.emit('stream:destroy'); }); setTimeout(stream.destroy, STREAM_TIMEOUT * 1000); });}
Ovenstående kode indeholder kernen i vores back-end. Når en anmodning er modtaget på /search, starter vi streamen ved hjælp af Twitters streaming-API, der returnerer et stream-objekt.
twit.stream('statuses/filter', {track:val}, function(stream) {});
Vi kan lytte til stream-objektet efter en nøgle kaldet "data", som sender os et nyt tweet, når det er tilgængeligt.
stream.on('data', function(data) {});
"Data"-objektet indeholder tweet-JSON, som kan se sådan ud (en del af svaret er udeladt):
{ "created_at":"Ons 26. jul 08:01:56 +0000 2017", "id":890119982641803300, "id_str":"890119982641803264", "text":\"RT Jim DeMintsNews Der er ingen bedre mand end Jeff Sessions, og ingen større tilhænger...af [præsident #Trumps] dagsorden.\"...", "kilde":"Twitter til Android ", "truncated":false, "in_reply_to_status_id":null, "in_reply_to_status_id_str":null, "in_reply_to_user_id":null, "in_reply_to_str_user null, "in_reply_to_str_user:"in_reply_to_screen_name":null, "user":{ "id":4833141138, "id_str":"4833141138", "name":"randy joe davis", "screen_name":"randyjoedavis1", "location":null, " url":null, "description":"Konservativ Patriot, pensioneret militær, pensioneret DOD civil. kvægfarmer, rytter, eventyrer. Lovin Life ! GO HOGS !!", "protected":false, "verified":false, "followers_count" ":226, "friends_count":346, "listed_count":0, "favourites_count":3751, "statuses_count":1339, "created_at":"lør jan. 30 03:39:16 +0000 2016", "utc_offset":null, "time_zone":null, "geo_enabled":false, "lang":"da", "contributors_enabled":false, "is_translator":false, " profile_background_color":"F5F8FA", "profile_background_image_url":"", "profile_background_image_url_https":"", "profile_background_tile":false, "profile_link_color":"1DA1F2", "profile_sidebar_border_color":"DEFfill_color"_side:_bar , "profile_text_color":"333333", "profile_use_background_image":true, "profile_image_url":"http://pbs.twimg.com/profile_images/883522005210943488/rqyyXlEX_image_image", "ur"lpbs.https://pbs.twimg.com_ twimg.com/profile_images/883522005210943488/rqyyXlEX_normal.jpg", "default_profile":true, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications}}Vi gemmer dette svar på en Redis-liste kaldet "tweets" ved hjælp af LPUSH:
client.lpush('tweets', JSON.stringify(data), function() {});
Når tweetet er blevet gemt, trimmer vi listen ved hjælp af LTRIM for at beholde et maks. antal tweets (så vores diskplads ikke bliver fuld):
client.ltrim('tweets', 0, TWEETS_TO_KEEP, function() {});
Efter at have trimmet listen henter vi det seneste tweet ved hjælp af LRANGE og sender det til front-end:
client.lrange('tweets', 0, 1, function(err, tweetListStr) { io.emit('savedTweetToRedis', JSON.parse(tweetListStr[0]));});
Da dette er et demoprogram, skal vi også manuelt ødelægge streamen efter et bestemt tidspunkt, så den ikke bliver ved med at skrive til disken:
stream.on('end', function(response) { io.emit('stream:destroy');});setTimeout(stream.destroy, STREAM_TIMEOUT * 1000);
Og du er færdig! Tænd serveren med npm start og nyd streamingoplevelsen.
En demo af applikationen er tilgængelig her: https://node-socket-redis-stream-tweet.herokuapp.com/
For at implementere denne applikation på Heroku, tjek deres dokumenter:https://devcenter.heroku.com/categories/deployment
Hele kildekoden er også tilgængelig på GitHub, så du kan fordele og arbejde på: https://github.com/Scalegrid/code-samples/tree/sg-redis-node-socket-twitter-search/node-socket-redis -twitter-hashtags
Som altid, hvis du bygger noget fantastisk, så tweet os om det @scalegridio.
Hvis du har brug for hjælp til administration og hosting af Redis™*, så kontakt os på [email protected] for yderligere information.