В тази статия ще изградим стрийминг списък с туитове въз основа на заявка за търсене, въведена от потребителя. Туитовете ще бъдат извлечени с помощта на API за стрийминг на Twitter, съхранени в списък на Redis и актуализирани в предния край с помощта на Socket.io. Основно ще използваме Redis като кеширащ слой за извличане на туитове.
Въведение
Ето кратко описание на технологиите, които ще използваме:
Redis
Redis е с отворен код (BSD лицензиран), хранилище за структура на данни в паметта, използвано като база данни, кеш и посредник на съобщения. Той поддържа структури от данни като низове, хешове, списъци, набори, сортирани набори със заявки за диапазон, растерни изображения, хиперлогове и геопространствени индекси със заявки за радиус.
Node.js
Node.js е платформа, изградена върху времето за изпълнение на JavaScript на Chrome за лесно изграждане на бързи и мащабируеми мрежови приложения. Node.js използва управляван от събития, неблокиращ I/O модел, който го прави лек и ефективен и по този начин идеален за приложения в реално време с интензивни данни, които работят на разпределени устройства.
Express.js
Express.js е рамка на Node.js. Можете да създадете сървърния и сървърния код за приложение като повечето други уеб езици, но с помощта на JavaScript.
Socket.IO
Socket.IO е JavaScript библиотека за уеб приложения в реално време. Той позволява двупосочна комуникация в реално време между уеб клиенти и сървъри. Той има две части:библиотека от страна на клиента, която работи в браузъра, и библиотека от страна на сървъра за Node.js. И двата компонента имат почти идентични API.
Героку
Heroku е облачна платформа, която позволява на компаниите да създават, доставят, наблюдават и мащабират приложения – това е най-бързият начин да преминете от идея към URL, заобикаляйки всички тези инфраструктурни главоболия.
Тази статия предполага, че вече имате Redis, Node.js и Heroku Toolbelt, инсталирани на вашата машина.
Настройка
– Изтеглете кода от следното хранилище: https://github.com/Scalegrid/code-samples/tree/sg-redis-node-socket-twitter-search/node-socket-redis-twitter-hashtags
- Изпълнете npm install, за да инсталирате необходимите компоненти
- И накрая, можете да стартирате сървъра на възел, като направите „node index.js“. Можете също да стартирате „nodemon“, който също следи за промени във файловете.
Можете също да получите достъп до хоствана версия на това приложение тук: https://node-socket-redis-stream-tweet.herokuapp.com/
Процесът
Ето кратко описание на процеса, който ще използваме за изграждане на демонстрационното приложение:
1. Ще започнем с приемане на заявка за търсене от потребителя. Заявката може да бъде споменавания в Twitter, хештагове или произволен текст за търсене.
2. След като имаме заявката за търсене, ще я изпратим до API за стрийминг на Twitter, за да извлечем туитове. Тъй като това е поток, ние ще слушаме, когато туитовете се изпращат от API.
3. Веднага след като туитът бъде извлечен, ще го съхраним в списък на Redis и ще го излъчим на предния край.
Какво представляват списъците на Redis?
Redis списъците се изпълняват чрез свързани списъци. Това означава, че дори ако имате милиони елементи вътре в списък, операцията по добавяне на нов елемент в началото или в края на списъка се извършва в постоянно време. Скоростта на добавяне на нов елемент с командата LPUSH към началото на списък с десет елемента е същата като добавянето на елемент към началото на списък с 10 милиона елемента.
В нашето приложение ние ще съхраняваме туитовете, получени чрез API, в списък, наречен „туитове“. Ще използваме LPUSH, за да избутаме новополучения туит в списъка, ще го изрежем с помощта на LTRIM, който ограничава размера на използваното дисково пространство (тъй като записването на поток може да отнеме много място), ще извлечем най-новия туит с помощта на LRANGE и ще го излъчим до предния край, където ще бъде добавен към списъка за поточно предаване.
Какво е LPUSH, LTRIM и LRANGE?
Това са набор от команди на Redis, които се използват за добавяне на данни към списък. Ето кратко описание:
LPUSH
Вмъкнете всички посочени стойности в началото на списъка, съхранен в ключ. Ако ключът не съществува, той се създава като празен списък преди извършване на операциите за натискане. Когато ключът съдържа стойност, която не е списък, се връща грешка.
redis> LPUSH mylist "world"(integer) 1redis> LPUSH mylist "hello"(integer) 2redis> LRANGE mylist 0 -11) "hello"2) "world"
LTRIM
Изрежете съществуващ списък, така че да съдържа само посочения диапазон от елементи. И стартът, и стопът са индекси, базирани на нула, където 0 е първият елемент от списъка (главата), 1 следващият елемент и така нататък.
redis> RPUSH mylist "one"(integer) 1redis> RPUSH mylist "two"(integer) 2redis> RPUSH mylist "three"(integer) 3redis> LTRIM mylist 1 -1"OK"redis> LRANGE mylist 0 -11 ) "две"2) "три"
LRANGE
Връща посочените елементи от списъка, съхранен в key. Началото и спирането на изместванията са индекси, базирани на нула, като 0 е първият елемент от списъка (главата на списъка), 1 е следващият и т.н.
Тези отмествания могат да бъдат и отрицателни числа, показващи позиции от края на списъка. Например -1 е последният елемент от списъка, -2 предпоследният и т.н.
redis> RPUSH mylist "one"(integer) 1redis> RPUSH mylist "two"(integer) 2redis> RPUSH mylist "three"(integer) 3redis> LRANGE mylist 0 01) "one"redis> LRANGE mylist -3 21 ) "едно"2) "две"3) "три"
Изграждане на приложението
Нашата демонстрация изисква както преден, така и заден край. Нашият преден край е доста просто текстово поле с бутон, който ще се използва за стартиране на потока.
$('body').on('click', '.btn-search', function() { $('#tweets_area').empty(); $(this).text('Стрийминг.. .').attr('disabled', true); $.ajax({ url:'/search', type:'POST', data:{ val:$.trim($('.search-txt'). val()) } });});
Нуждаем се от помощна функция, за да изградим кутия за туитове, след като получим туит от нашия бекенд:
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 +='
Също така имаме нужда от слушател, който да спре потока и да предотврати добавянето на повече туитове към списъка за стрийминг:
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);});
Нека преминем към задната част на нещата и да започнем да пишем нашия /search API.
/** * API - Търсене */app.post('/search', function(req, res, next) { _searchTwitter(req.body.val); res.send({ status:'OK' } );});/** * Предаване на данни от Twitter за въвеждане на текст * * 1. Използвайте API за поточно предаване на Twitter, за да проследите конкретна стойност, въведена от потребителя * 2. След като имаме данните от Twitter, добавете ги към Redis списък с помощта на LPUSH * 3. След добавяне към списъка, ограничете списъка с помощта на LTRIM, така че потокът да не препълва диска * 4. Използвайте LRANGE, за да извлечете най-новия туит и да го издадете към предния край, като използвате Socket.io * * @ param {String} val Низ на заявката * @return */var _searchTwitter =function(val) { twit.stream('statuses/filter', {track:val}, function(stream) { stream.on('data', function) (данни) { 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); });}
Горният код съдържа ядрото на нашия бекенд. След като бъде получена заявка в /search, ние стартираме потока, използвайки API за стрийминг на Twitter, който връща обект на поток.
twit.stream('statuses/filter', {track:val}, function(stream) {});
Можем да слушаме обекта на потока за ключ, наречен „данни“, който ще ни изпрати нов туит, когато е наличен.
stream.on('data', function(data) {});
Обектът „data“ съдържа tweet JSON, който може да изглежда така (част от отговора е пропусната):
{ "created_at":"Сряда, 26 юли 08:01:56 +0000 2017", "id":890119982641803300, "id_str":"890119982641803264", "text":"RT News:@Fox Няма по-добър човек от Джеф Сешънс и няма по-голям поддръжник... на дневния ред на [президента #Тръмп].\"… ", "source":"Twitter за Android ", "truncated":false, "in_reply_to_status_id":null, "in_reply_to_status_id_str":null, "in_reply_to_user_id":null, "to_reply_u":null, "in_reply_u" "in_reply_to_screen_name":null, "user":{ "id":4833141138, "id_str":"4833141138", "name":"randy joe davis", "screen_name":"randyjoedavis1", "location":null, " url":null, "description":"Консервативният патриот, пенсиониран военен, пенсиониран цивилен служител на DOD. животновъд, конник, авантюрист. 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":"Съб януари 30 03:39:16 +0000 2016", "utc_offset":null, "time_zone":null, "geo_enabled":false, "lang":"en", "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_DEE_color":"profile_sidebar_border_DEEF6", "profile_sidebar_border_DEF6":, "profile_text_color":"333333", "profile_use_background_image":true, "profile_image_url":"http://pbs.twimg.com/profile_images/883522005210943488/rqyyXlEX:profile_pbs://pbs.twimg.com/profile_images/883522005210943488/rqyyXlEX:url_normal. twimg.com/profile_images/883522005210943488/rqyyXlEX_normal.jpg", "default_profile":true, "default_profile_image":false, "following":null, "follow_request_sent", "null null":"null":Съхраняваме този отговор в списък на Redis, наречен „туитове“, използвайки LPUSH:
client.lpush('tweets', JSON.stringify(data), function() {});След като туитът бъде запазен, ние изрязваме списъка с помощта на LTRIM, за да запазим максимален брой туитове (така че дисковото ни пространство да не се запълни):
client.ltrim('tweets', 0, TWEETS_TO_KEEP, function() {});След подрязване на списъка, ние извличаме най-новия туит с помощта на LRANGE и го излъчваме към предния край:
client.lrange('tweets', 0, 1, function(err, tweetListStr) { io.emit('savedTweetToRedis', JSON.parse(tweetListStr[0]));});Тъй като това е демонстрационно приложение, ние също трябва ръчно да унищожим потока след определено време, за да не продължи да записва на диска:
stream.on('end', function(response) { io.emit('stream:destroy');});setTimeout(stream.destroy, STREAM_TIMEOUT * 1000);И сте готови! Стартирайте сървъра с помощта на npm start и се насладете на стрийминг изживяването.
Демо на приложението е достъпно тук: https://node-socket-redis-stream-tweet.herokuapp.com/
За да внедрите това приложение на Heroku, вижте техните документи:https://devcenter.heroku.com/categories/deployment
Целият изходен код също е достъпен в GitHub, за да можете да се разклоните и да работите върху: https://github.com/Scalegrid/code-samples/tree/sg-redis-node-socket-twitter-search/node-socket-redis -туитър-хаштагове
Както винаги, ако създадете нещо страхотно, туитнете ни за това @scalegridio.
Ако имате нужда от помощ за управление и хостинг за Redis™*, свържете се с нас на [email protected] за допълнителна информация.