LoginSignup
1
1

More than 5 years have passed since last update.

Slackでよく使われる単語をまとめてみた

Last updated at Posted at 2018-12-08

こんにちは、フィッシュです🐟業務や趣味でGCPを触っている釣り好きエンジニアです。GCPと釣りの融合で Cloud AutoML Visionを使ってカレイの種類を識別 とかやってます。最近Goを触りはじめたので表題のスクリプトをGoで書いてみました。

やったこと

  • Slack APIからチャンネルの会話ログを取得する
  • 会話のログを品詞分解し単語を取り出す
  • 同じ単語の数を数えて配列を作る
  • その配列を並び替えてログ出力する

Slack APIからチャンネルの会話ログを取得する

まずはこちらからチャンネルの会話ログを取得してみましょう。

取得方法

  • ワークスペースを選択する
  • 取得したいチャンネルを選択する 例 #general
  • countを1000にする
  • 上記の入力が終えたら Test Methodをクリックする
  • リクエストURLとレスポンスが表示されます
  • リクエストURLをどこかに控えておきます

Screen Shot 2018-12-08 at 11.19.45.png

Goで上記のURLを叩く

main.go
package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
)

type Message struct {
    Text string `json:"text"`
}

type Channel struct {
    Messages []Message `json:"messages"`
}

func main() {
    // 控えたURLを入れる
    url := "https://slack.com/api/channels.history?token="
    res, err := http.Get(url)
    if err != nil {
        log.Fatal(err)
    }
    if res.StatusCode != 200 {
        return
    }

    defer res.Body.Close()
    var c Channel
    decoder := json.NewDecoder(res.Body)
    err = decoder.Decode(&c)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(c)
}

会話のログを品詞分解し単語を取り出す

上記で取得したログは文章になっているので、そこから単語だけを抽出します。品詞分解には mecabを使います。Go向けにラッピングされたソースがあるのでこちらを使います。ありがたやー
https://github.com/bluele/mecab-golang

mecabを準備

$ brew insatll mecab mecab-ipadic

$ which mecab-config
/usr/local/bin/mecab-config //こんな感じになればOK

// 環境変数を作成
$ export CGO_LDFLAGS="`mecab-config --libs`"
$ export CGO_CFLAGS="-I`mecab-config --inc-dir`"

Goでmecabを使って品詞分解

APIでテキストを取得し、その中から3文字以上の名詞だけを取り出します。

main.go
package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "strings"
    "unicode/utf8"

    "github.com/bluele/mecab-golang"
)

type Message struct {
    Text string `json:"text"`
}

type Channel struct {
    Messages []Message `json:"messages"`
}

func main() {
...中略

    m, err := mecab.New("-Owakati")
    if err != nil {
        fmt.Printf("Mecab instance error. err: %v", err)
    }
    defer m.Destroy()
    decoder := json.NewDecoder(res.Body)
    err = decoder.Decode(&c)
    if err != nil {
        log.Fatal(err)
    }

    var tmp []string
    for _, msg := range c.Messages {
        parseToNode(m, msg.Text, &tmp)
    }

    fmt.Println(tmp)
}

func parseToNode(m *mecab.MeCab, s string, t *[]string) {
    tg, err := m.NewTagger()
    if err != nil {
        panic(err)
    }
    defer tg.Destroy()
    lt, err := m.NewLattice(s)
    if err != nil {
        panic(err)
    }
    defer lt.Destroy()

    node := tg.ParseToNode(lt)
    for {
        features := strings.Split(node.Feature(), ",")
        if utf8.RuneCountInString(features[6]) > 2 {
            if features[0] == "名詞" {
                *t = append(*t, features[6])
            }
        }
        if node.Next() != nil {
            break
        }
    }
}

こんな感じのログが出力される

$ [こちら 結婚式 土曜日 日曜日 結婚式 チャンネル]

同じ単語の数を数えて配列を作る

このままだと普通の文字配列なので同じ単語をカウント付きでまとめます

main.go
...中略
type Buzzword struct {
    Word  string
    Count int
}

func main() {
...中略
    var buzzwords []Buzzword
    for word, count := range wordCount(tmp) {
        buzzwords = append(buzzwords, Buzzword{word, count})
    }
    fmt.Println(buzzwords)
}

func wordCount(a []string) map[string]int {
    c := make(map[string]int)
    for _, word := range a {
        c[word]++
    }
    return c
}

結果例

$ [{お答え 1} {大丈夫 10} {どちら 2} {どっち 1} {タイミング 3} {マグロ 2}]

どの単語がいくつ入っているところまで分かりました!

並び替えをして完成

並び替えはこんな感じで実装しました

main.go
package main

import (
    "log"
    "sort"
)

type Buzzword struct {
    Word  string
    Count int
}

type Buzzwords []Buzzword

func (p Buzzwords) Len() int {
    return len(p)
}

func (p Buzzwords) Swap(i, j int) {
    p[i], p[j] = p[j], p[i]
}

type ByCount struct {
    Buzzwords
}

func (b ByCount) Less(i, j int) bool {
    return b.Buzzwords[i].Count > b.Buzzwords[j].Count
}

func main() {
    var people Buzzwords = []Buzzword{
        {"お答え", 1},
        {"大丈夫", 10},
        {"どちら", 2},
        {"どっち", 1},
        {"タイミング", 3},
        {"マグロ", 2},
    }

    sort.Sort(ByCount{people})
    log.Println(people)
}

多い順に並び替わります

$ [{大丈夫 10} {タイミング 3} {どちら 2} {マグロ 2} {お答え 1} {どっち 1}]

よくうろうろしているSlackの結果はこんな感じ

チャンネル => 92
お願い => 58
イベント => 57
こちら => 24
オンライン => 22
申し込み => 16
みたい => 16
ページ => 14
スピーカー => 13
大丈夫 => 10
コード => 9
みんな => 9
レポート => 7
カレー => 7
フォーム => 7
スライド => 7
セッション => 7
みなさん => 7
トピック => 6

参考になったリンク

全部入りのソースコード

上記のソースコードを突っ込んだ main.go をGitHubにあげました。とくにリファクタリングなどしていないので、変なところがあったらIssueとかプルリクエストを貰えると嬉しいです:)

1
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1