ある日、Golang WeeklyメーリングリストでBleveプロジェクトに出会いました。 これは、Goで記述された全文検索です。 このプロジェクトは興味深いものであり、それを体験したいという必死の欲求がありました。
Bleveは、さまざまな組み込みデータベースにデータを保存できます。
- BoltDB(デフォルトで使用)
- Leveldb
- RocksDB
- Goleveldb
- forestdb
- グトレープ
Bleveは次の製品との連携が簡単です。
import "github.com/blevesearch/bleve" func main() { // mapping := bleve.NewIndexMapping() index, err := bleve.New("example.bleve", mapping) // err = index.Index(identifier, your_data) // - query := bleve.NewMatchQuery("text") search := bleve.NewSearchRequest(query) searchResults, err := index.Search(search) }
すべてがシンプルで明確です。 しかし、現実の世界からは見えません。 現実の世界に近づけるために、ストーリーを保持するSlackのボットを作成します。
ボットのアーキテクチャ
スラックを扱うためのサービス。
サービスインデックス。 メッセージの保存および検索用。
計画
- スラックを操作するにはhttps://api.slack.com/methods/channels.historyを使用します。
- Bleveを使用して履歴を検索および保存します。
- ボットのボットに基づいていないメッセージが送信されていない場合、インデックスに入れます。
- コマンドでメッセージが到着した場合-現在のチャネルをクリーニングして検索します。
たるみ
スラックを使用すると、すべてがシンプルになり、実際の例はレポの例よりも少し複雑になります
必要なのは、メッセージがボット宛てかどうかを確認し、ボットに代わってクリアする2つの方法だけです
import "strings" func isToMe(message string) bool { return strings.Contains(message, fmt.Sprintf("<@%s>", ss.me)) } func cleanMessage(message string) string { return strings.Replace(message, fmt.Sprintf("<@%s> ", ss.me), "", -1) }
ブリーブ
私はgoleveldbをプロジェクトの組み込みデータベースとして使用したいと考えています。 このプロジェクトでは、自分で使用することにしました。
以下の形式で、より複雑なデータをBleveに保存します。
type IndexData struct { ID string `json:"id"` Username string `json:"username"` Message string `json:"message"` Channel string `json:"channel"` Timestamp string `json:"timestamp"` }
Goleveldbをデータベースとして使用してインデックスを作成します。
import ( "github.com/blevesearch/bleve" "github.com/blevesearch/bleve/index/store/goleveldb" ) func createIndex() (bleve.Index, error) { indexName := "history.bleve" index, err := bleve.Open(indexName) if err == bleve.ErrorIndexPathDoesNotExist { mapping := buildMapping() kvStore := goleveldb.Name kvConfig := map[string]interface{}{ "create_if_missing": true, } index, err = bleve.NewUsing(indexName, mapping, "upside_down", kvStore, kvConfig) } if err != nil { return err } }
そしてbuildMappingメソッドは、保存するためのマッピングを作成します:
func (ss *SearchService) buildMapping() *bleve.IndexMapping { ruFieldMapping := bleve.NewTextFieldMapping() ruFieldMapping.Analyzer = ru.AnalyzerName eventMapping := bleve.NewDocumentMapping() eventMapping.AddFieldMappingsAt("message", ruFieldMapping) mapping := bleve.NewIndexMapping() mapping.DefaultMapping = eventMapping mapping.DefaultAnalyzer = ru.AnalyzerName return mapping }
検索ではすべてが少し複雑です:
func (ss *SearchService) Search(query, channel string) (*bleve.SearchResult, error) { stringQuery := fmt.Sprintf("/.*%s.*/", query) // NewTermQuery Query , ch := bleve.NewTermQuery(channel) // Query . . . . . mq := bleve.NewMatchPhraseQuery(query) // Query rq := bleve.NewRegexpQuery(query) // Query , . qsq := bleve.NewQueryStringQuery(stringQuery) // Query Query. q := bleve.NewDisjunctionQuery([]bleve.Query{ch, mq, rq, qsq}) search := bleve.NewSearchRequest(q) search.Fields = []string{"username", "message", "channel", "timestamp"} return ss.index.Search(search) }
それをすべてまとめると、ストーリーを保存し、ElasticSearch、Solrの例を重くすることなく検索できるボットが得られます。
Githubで利用可能な完全なプロジェクトコード