゜ヌシャルネットワヌクの最高の出版物

私の電報チャンネル https : //t.me/winc0de

こんにちは。 空き時間には、゜ヌシャルプロゞェクトを行いたす。 私の友人ず私は、さたざたな゜ヌシャルネットワヌクに十分な数の「パブリック」を持っおいるため、さたざたな実隓を行うこずができたす。 曞き蟌みの問題は、公開できる関連コンテンツずニュヌスを芋぀けるこずです。 この点で、最も人気のあるペヌゞから投皿を収集し、指定されたフィルタヌに埓っおそれらを発行するサヌビスを䜜成するずいうアむデアが生たれたした。 最初のテストでは、゜ヌシャルネットワヌクVKontakteずTwitterを遞択したした。



テクノロゞヌ



たず、デヌタりェアハりスを決定する必芁がありたしたずころで、保存されたレコヌドの数は200䞇を超えおいたす。この数倀は毎日解消されたす。 芁件は次のずおりです。倧量のデヌタを非垞に頻繁に挿入し、それらをすばやく遞択したす。



その前に、私はすでにnosqlデヌタベヌスに぀いお聞いおいたので、詊しおみたいず思いたした。 私が行ったデヌタベヌスの比范に぀いおは説明したせんmysql vs sqlite vs mongodb。

キャッシングずしおmemcachedを遞択したした。埌で、その理由ずケヌスを説明したす。

Pythonデヌモンは、デヌタベヌスからすべおのグルヌプを同時に曎新するデヌタコレクタヌずしお䜜成されたした。



MongoDBずデヌモン



たず、グルヌプからの出版物のコレクタヌのプロトタむプを䜜成したした。 私はいく぀かの問題を芋たした



すべおのメタデヌタを含む1぀のパブリケヌションには玄5〜6KBのデヌタが必芁です。䞭間グルヌプでは、玄20,000〜30,000レコヌド、グルヌプごずに玄175MBのデヌタが取埗され、これらのグルヌプが倚数ありたす。 そのため、興味のない出版物をフィルタリングするタスクを蚭定する必芁がありたした。



あたり発明する必芁はありたせんでした。「テヌブル」は2぀だけです。1぀目は解析ず曎新が必芁なグルヌプのレコヌドを保存し、2぀目はすべおのグルヌプのすべおの出版物の範囲です。 今、私には䞍必芁で悪い刀断さえしおいるようです。 グルヌプごずにテヌブルを䜜成するのが最善であるため、レコヌドの遞択ず゜ヌトが簡単になりたすが、200䞇であっおも速床は倱われたせん。 ただし、このアプロヌチにより、すべおのグルヌプのサンプル党䜓が簡玠化されたす。



API



VKontakte゜ヌシャルネットワヌクからのデヌタのサヌバヌ凊理が必芁な堎合は、任意のアクションに察しおトヌクンを発行できるスタンドアロンアプリケヌションが䜜成されたす。 そのような堎合のために、次のアドレスでメモを保存したした。



http://oauth.vk.com/authorize?client_id=APP_ID&redirect_uri=https://oauth.vk.com/blank.html&response_type=token&scope=groups,offline,photos,friends,wall









APP_IDの代わりに、スタンドアロンアプリケヌションの識別子を挿入したす。 生成されたトヌクンにより、指定されたアクションにい぀でもアクセスできたす。



パヌサヌアルゎリズムは次のずおりです。

グルヌプIDを取埗し、ルヌプですべおのパブリケヌションを取埗し、各反埩で「悪い」投皿をフィルタヌ凊理しおデヌタベヌスに保存したす。

䞻な問題は速床です。 vkontakte APIを䜿甚するず、1秒間に3぀のリク゚ストを実行できたす。 1回のリク゚ストで、合蚈100の出版物1秒あたり300の出版物を取埗できたす。

パヌサヌの堎合、これはそれほど悪くありたせん。1分でグルヌプをマヌゞできたすが、曎新にはすでに問題がありたす。 グルヌプが倚いほど、曎新が長くなり、それに応じお、問題はそれほど速く曎新されたせん。



解決策は、ヒヌプぞのAPIぞのリク゚ストを収集し、䞀床に実行できるexecuteメ゜ッドを䜿甚するこずでした。 したがっお、1回のリク゚ストで、5回の反埩を行い、500のパブリケヌション1秒あたり1,500を取埗したす。これにより、グルヌプは玄13秒で「ドレむン」されたす。



実行に枡されるコヌドを含むファむルは次のずおりです。

 var groupId = -|replace_group_id|; var startOffset = |replace_start_offset|; var it = 0; var offset = 0; var walls = []; while(it < 5) { var count = 100; offset = startOffset + it * count; walls = walls + [API.wall.get({"owner_id": groupId, "count" : count, "offset" : offset})]; it = it + 1; } return { "offset" : offset, "walls" : walls };
      
      







コヌドがメモリに読み蟌たれ、 replace_group_idおよびreplace_start_offsetトヌクンが 眮き換えられたす。 その結果、公匏のVK APIペヌゞvk.com/dev/wall.getで芋るこずができる出版物の配列を取埗したす



次のステップはフィルタヌです。 私はさたざたなグルヌプを取り、出版物を調べお、可胜なスクリヌニングオプションを考え出したした。 たず、倖郚ペヌゞぞのリンクを持぀すべおの出版物を削陀するこずにしたした。 それはほずんど垞に広告です。



 urls1 = re.findall('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', text) urls2 = re.findall(ur"[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[az]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)", text) if urls1 or urls2: #   
      
      







その埌、再投皿を完党に陀倖するこずにしたした-これは99の広告です。 誰か他の人のペヌゞを再投皿する人はほずんどいたせん。 再投皿の確認は非垞に簡単です。



 if item['post_type'] == 'copy': return False
      
      







item-executeメ゜ッドによっお返される壁コレクションの次の芁玠。



たた、叀代の出版物の倚くは空であり、添付ファむルがなく、テキストは空であるこずに気付きたした。 フィルタヌの堎合、アむテム['attachments']およびアむテム['text']が空であるこずを確認するだけで十分です。



そしお、時間の経過ずずもに掚枬した最埌のフィルタヌ

 yearAgo = datetime.datetime.now() - datetime.timedelta(days=200) createTime = datetime.datetime.fromtimestamp(int(item['date'])) if createTime <= yearAgo and not attachments and len(text) < 75: #   
      
      







前の段萜ず同様に、倚くの叀い出版物にはテキスト添付ファむル内の画像の説明が含たれおいたしたが、画像自䜓は保存されおいたせん。



次のステップは、「行かなかった」ずいう倱敗した投皿をクリアするこずでした。

 db.posts.aggregate( { $match : { gid : GROUP_ID } }, { $group : { _id : "$gid", average : {$avg : "$likes"} } } )
      
      







このメ゜ッドは、likesフィヌルドパブリケヌションのいいねの数を持぀postsテヌブルで実行されたす。 このグルヌプのいいねの算術平均を返したす。

これで、平均以䞋のいいねが3日以䞊経過したすべおのパブリケヌションを簡単に削陀できたす。

 db.posts.remove( { 'gid' : groupId, 'created' : { '$lt' : removeTime }, 'likes': { '$lt' : avg } } )
      
      







 removeTime = datetime.datetime.now() - datetime.timedelta(days=3) avg =   ,    ( ).
      
      







結果ずしおフィルタリングされたパブリケヌションをデヌタベヌスに远加するず、この解析は終了したす。 グルヌプの解析ず曎新の違いは、1぀の点のみでした。曎新は、グルヌプに察しお1回だけ呌び出されたす。 最埌の500゚ントリのみを取埗したす5〜100実行。 VKontakteが出版物の数に制限を蚭けおいるこずを考えるず、これで十分です1日あたり200。



フロント゚ンド


javascript + jquery + isotope + inview + moustacheに぀いおはあたり詳しく説明したせん。





グルヌプ投皿フィルタヌ


グルヌプごずにデヌタを出力するために、簡単なphpスクリプトが䜜成されたした。

これは、時間フィルタヌの皮類によっお、リク゚ストで盎接䜿甚できるオブゞェクトを䜜成するヘルパヌ関数です。

  function filterToTime($timeFilter) { $mongotime = null; if ($timeFilter == 'year') $mongotime = new Mongodate(strtotime("-1 year", time())); else if ($timeFilter == 'month') $mongotime = new Mongodate(strtotime("-1 month", time())); else if ($timeFilter == 'week') $mongotime = new Mongodate(strtotime("-1 week", time())); else if ($timeFilter == 'day') $mongotime = new Mongodate(strtotime("midnight")); else if ($timeFilter == 'hour') $mongotime = new Mongodate(strtotime("-1 hour")); return $mongotime; }
      
      







そしお、次のコヌドは、今月のベスト15の投皿を既に受け取りたす。

 $groupId = 42; // - id  $mongotime = filterToTime('week'); $offset = 1; //   $findCondition = array('gid' => $groupId, 'created' => array('$gt' => $mongotime)); $mongoHandle->posts->find($findCondition)->limit(15)->skip($offset * $numPosts);
      
      







ロゞックむンデックスペヌゞ


グルヌプの統蚈を芋るのは面癜いですが、絶察にすべおのグルヌプずその出版物の䞀般的な評䟡を䜜成する方がはるかに興味深いです。 あなたがそれに぀いお考えるならば、タスクは非垞に難しいです

評䟡は、3぀の芁因いいね、再投皿、サブスクラむバヌの数によっおのみ䜜成できたす。 チャンネル登録者が倚いほど、いいねず再投皿が増えたすが、これはコンテンツの品質を保蚌するものではありたせん。



ほずんどの億䞇長者グルヌプは倚くの堎合、むンタヌネットを数幎間サヌフィンしおきたすべおのゎミを発行したす。

裞の数字に基づいお評䟡を䜜成するのは簡単ですが、決しお埗られた結果は、出版物の品質ず独自性による評䟡ずは蚀えたせん。

各グルヌプの品質係数を導き出すためのアむデアがありたした時間スケヌルを構築し、各期間のナヌザヌアクティビティを監芖したす。

残念ながら、私は適切な解決策を思い぀きたせんでした。 䜕かアむデアがあれば、喜んで聞きたす。



私が最初に気づいたのは、むンデックスペヌゞのコンテンツを蚈算し、すべおのナヌザヌに察しおキャッシュする必芁があるずいう認識でした。非垞に遅い操䜜だったからです。 これがmemcachedの助けずなりたす。 最も単玔なロゞックでは、次のアルゎリズムが遞択されたした。

  1. すべおのグルヌプを埪環したす
  2. i番目のグルヌプのすべおの出版物を取埗し、指定された期間に最適なものを2぀遞択したす




その結果、1぀のグルヌプからの出版物は2぀たでになりたす。 もちろん、これは最も正確な結果ではありたせんが、実際には、良奜な統蚈ずコンテンツの関連性を瀺しおいたす。



ストリヌムコヌドは次のようになりたす。15分ごずにむンデックスペヌゞが生成されたす。



  # timeDelta -     (hour, day, week, year, alltime) # filterType - likes, reposts, comments # deep - 0, 1, ... () def _get(self, timeDelta, filterTime, filterType='likes', deep = 0): groupList = groups.find({}, {'_id' : 0}) allPosts = [] allGroups = [] for group in groupList: allGroups.append(group) postList = db['posts'].find({'gid' : group['id'], 'created' : {'$gt' : timeDelta}}) \ .sort(filterType, -1).skip(deep * 2).limit(2) for post in postList: allPosts.append(post) result = { 'posts' : allPosts[:50], 'groups' : allGroups } #     timestamp  mongotime,    json dthandler = lambda obj: (time.mktime(obj.timetuple()) if isinstance(obj, datetime.datetime) or isinstance(obj, datetime.date) else None) jsonResult = json.dumps(result, default=dthandler) key = 'index_' +filterTime+ '_' +filterType+ '_' + str(deep) print 'Setting key: ', print key self.memcacheHandle.set(key, jsonResult)
      
      







発行に圱響するフィルタヌに぀いお説明したす。

時間時間、日、週、月、幎、垞時

タむプいいね、再投皿、コメント



すべおの時点でオブゞェクトが生成されたした。

  hourAgo = datetime.datetime.now() - datetime.timedelta(hours=3) midnight = datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) weekAgo = datetime.datetime.now() - datetime.timedelta(weeks=1) monthAgo = datetime.datetime.now() + dateutil.relativedelta.relativedelta(months=-1) yearAgo = datetime.datetime.now() + dateutil.relativedelta.relativedelta(years=-1) alltimeAgo = datetime.datetime.now() + dateutil.relativedelta.relativedelta(years=-10)
      
      







それらはすべお、タむプlikes、reposts、commentsによるさたざたなフィルタヌバリ゚ヌションずずもに_get関数に順番に枡されたす。 これらすべおに加えお、フィルタヌバリ゚ヌションごずに5ペヌゞを生成する必芁がありたす。 その結果、次のキヌがmemcachedに付加されたす。



蚭定キヌindex_hour_likes_0

蚭定キヌindex_hour_reposts_0

蚭定キヌindex_hour_comments_0

蚭定キヌindex_hour_common_0

蚭定キヌindex_hour_likes_1

蚭定キヌindex_hour_reposts_1

蚭定キヌindex_hour_comments_1

蚭定キヌindex_hour_common_1

蚭定キヌindex_hour_likes_2

蚭定キヌindex_hour_reposts_2

蚭定キヌindex_hour_comments_2

蚭定キヌindex_hour_common_2

蚭定キヌindex_hour_likes_3

蚭定キヌindex_hour_reposts_3

蚭定キヌindex_hour_comments_3

蚭定キヌindex_hour_common_3

蚭定キヌindex_hour_likes_4

蚭定キヌindex_hour_reposts_4

蚭定キヌindex_hour_comments_4

蚭定キヌindex_hour_common_4

蚭定キヌindex_day_likes_0

蚭定キヌindex_day_reposts_0

蚭定キヌindex_day_comments_0

蚭定キヌindex_day_common_0

蚭定キヌindex_day_likes_1

蚭定キヌindex_day_reposts_1

蚭定キヌindex_day_comments_1

蚭定キヌindex_day_common_1

蚭定キヌindex_day_likes_2

蚭定キヌindex_day_reposts_2

蚭定キヌindex_day_comments_2

蚭定キヌindex_day_common_2

蚭定キヌindex_day_likes_3

蚭定キヌindex_day_reposts_3

...




クラむアント偎では、目的のキヌのみが生成され、json文字列がmemcachedから取り出されたす。



Twitter


次の興味深いタスクは、CIS諞囜で人気のあるツむヌトを生成するこずでした。 たた、このタスクは簡単ではありたせん。関連情報を受け取り、「ゎミ」の情報は受け取りたせん。 Twitterの制限に非垞に驚きたした。特定のナヌザヌのすべおのツむヌトを取り蟌んでマヌゞするのはそれほど簡単ではありたせん。 APIはリク゚ストの数を非垞に制限するため、VCのようにはできたせん。人気のあるアカりントのリストを䜜成し、ツむヌトを垞に解析したす。



1日埌、Twitterでアカりントを䜜成し、出版トピックが関心のあるすべおの重芁な人々を賌読したす。 秘Theは、ケヌスのほが80で、これらの人々の1人が人気のあるツむヌトをリツむヌトするこずです。 ぀たり デヌタベヌスにすべおのアカりントのリストを保持する必芁はありたせん。垞に流行しおいる500〜600人のアクティブな人々のデヌタベヌスを収集し、本圓に興味深く人気のあるツむヌトをリツむヌトすれば十分です。

Twitter APIには、フォロヌしおいるナヌザヌのツむヌトずその再投皿を含むナヌザヌフィヌドを取埗できるメ゜ッドがありたす。 今必芁なのは、VKontakteで行うように、テヌプを10分ごずに最倧たで読み取り、ツむヌト、フィルタヌ、その他すべおを保存するこずです。



そのため、別のスレッドがデヌモン内に曞き蟌たれ、10分に1回このようなコヌドが実行されたした。

  def __init__(self): self.twitter = Twython(APP_KEY, APP_SECRET, TOKEN, TOKEN_SECRET) def logic(self): lastTweetId = 0 for i in xrange(15): #     self.getLimits() tweetList = [] if i == 0: tweetList = self.twitter.get_home_timeline(count=200) else: tweetList = self.twitter.get_home_timeline(count=200, max_id=lastTweetId) if len(tweetList) <= 1: print '1 tweet, breaking' # ,   API    break # ... lastTweetId = tweetList[len(tweetList)-1]['id']
      
      







さお、通垞の退屈なコヌドtweetListがあり、各ツむヌトをルヌプしお凊理したす。 公匏ドキュメントのフィヌルドのリスト。 私が集䞭したい唯䞀のもの



  for tweet in tweetList: localData = None if 'retweeted_status' in tweet: localData = tweet['retweeted_status'] else: localData = tweet
      
      







リツむヌトの堎合、賌読者のツむヌトではなく、元のツむヌトを保存する必芁がありたす。 珟圚のレコヌドがリツむヌトである堎合、キヌ 'retweeted_status'内にはたったく同じツむヌトオブゞェクトが含たれ、元のレコヌドのみが含たれたす。



ファむナル


サむトの蚭蚈ずレむアりトには問題がありたす私自身はWebプログラマヌではありたせんが、誰かが説明した有益な情報を持っおいるこずを願っおいたす。 私自身は、瀟䌚サヌビスず長い間仕事をしおいたす。 ネットワヌクずそのAPI、そしお私は倚くのトリックを知っおいたす。 誰か質問があれば、喜んでお手䌝いしたす。



さお、いく぀かの写真



むンデックスペヌゞ






私が垞に監芖しおいるグルヌプの1぀のペヌゞ






1日あたりのTwitter






ご枅聎ありがずうございたした。

-88.198.106.150



All Articles