昨天我們處理搜尋的分頁方案,避免 from+size 帶來的效能問題。接下來要做的,就是把一個「真正規模」的資料集放進 Elasticsearch,讓我們能實際測試效能。
從 Kaggle 挑選公開資料集:Jeopardy! 問答題庫,包含數十萬筆問題、答案、金額,適合當作搜尋的題材。
到 Kaggle 下載資料集 JEOPARDY_CSV.csv,我們只需要幾個欄位:
Question:題目Answer:正解Category:題目所屬分類Value:題目的分數(難度指標)我們先寫個小工具,把 CSV 轉成 Elasticsearch Bulk API 格式
package main
import (
"encoding/csv"
"encoding/json"
"log"
"os"
"strconv"
)
type Jeopardy struct {
Question string `json:"question"`
Answer string `json:"answer"`
Category string `json:"category"`
Value int `json:"value"`
}
func main() {
f, err := os.Open("JEOPARDY_CSV.csv")
if err != nil {
log.Fatal(err)
}
defer f.Close()
reader := csv.NewReader(f)
records, err := reader.ReadAll()
if err != nil {
log.Fatal(err)
}
out, _ := os.Create("bulk_jeopardy.ndjson")
defer out.Close()
for i, row := range records {
if i == 0 { // skip header
continue
}
value := 0
if row[3] != "" {
val, err := strconv.Atoi(row[3])
if err == nil {
value = val
}
}
doc := Jeopardy{
Question: row[1],
Answer: row[2],
Category: row[3],
Value: value,
}
meta := map[string]map[string]string{
"index": {"_index": "jeopardy"},
}
mj, _ := json.Marshal(meta)
dj, _ := json.Marshal(doc)
out.Write(mj)
out.Write([]byte("\n"))
out.Write(dj)
out.Write([]byte("\n"))
}
}
這樣會輸出一個 bulk_jeopardy.ndjson,裡面長這樣:
{"index":{"_index":"jeopardy"}}
{"question":"For the last 8 years of his life, Galileo was under house arrest for espousing this man's theory","answer":"Copernicus","category":"HISTORY","value":200}
{"index":{"_index":"jeopardy"}}
{"question":"The city of Yuma in this state has a record average of 4,055 hours of sunshine each year","answer":"Arizona","category":"GEOGRAPHY","value":400}
Bulk API 可以用 curl 直接送:
curl -H "Content-Type: application/x-ndjson" -XPOST "localhost:9200/_bulk?pretty" --data-binary "@bulk_jeopardy.ndjson"
如果檔案有十幾萬筆,可以分批(例如 5000 筆一批)送進去,避免請求太大。
匯入後,可以測試一下:
curl "localhost:9200/jeopardy/_count"
預期應該會有 20 萬筆以上。
還可以做個簡單的查詢,例如找關於「Shakespeare」的題目:
curl -X GET "localhost:9200/jeopardy/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match": {
"question": "Shakespeare"
}
}
}
'
到這裡,我們終於把一個「真實規模」的資料集放進 Elasticsearch,完成了 Day 20 的目標。
這不只是練習 API,而是讓我們的搜尋服務 可以被實際驗證。
從這一步開始,我們有了基礎: