# L2H-HW
## 1. The query you use to setup the index settings
### ANS:
#### Create Index
##### Command
<pre><code>PUT /jobs
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
},
"mappings": {
"properties": {
"Name": { "type": "text" },
"Job": { "type": "text" },
"Age": { "type": "integer" },
"Gender": { "type": "text" }
}
}
}</code></pre>
#### Check settings are working
##### Command
<pre><code>GET _cat/shards?h=index,shard</code></pre>
##### Result

## 2. Screenshot of the index settings and the screenshot of the dashboard you created.
### ANS
#### My Sample Index: Jobs

#### Dashboard made by data sources including amazon.books.json and steam.games.json

## 3. Details of how you process the data
### ANS
我將這個 Load資料的過程分成三個部分包含單次跟批次處理,最後一段則是使用第二份遊戲的資料。
#### Stage 1. Single Test
1. 先將 Repository Clone下來,確認資料的長相,我複製了一份檔案,擷取了 **_id** = 1 的 document做測試。
1. 選擇用 Python API json講文字轉換成 Json,在確認可行性的過程中有遇到引號需要跳脫,用 Replace處理。
1. 最後確認此資料 amazon.books.json可以被轉換成 431個 Document(Dictionary)。
1. 為了先得到一個動態生成的 Mappings,使用 Elasticsearch的 API 傳入一個 Document。
1. 由於先前用 Dev Tool測試,得知 **_id**是 Metadata Field,塞入資料時會觸及 Error,根據 API引數說明,可以代在 Function裡面,所以在 輸入資料前將 **_id** POP出來再執行。<pre>document.pop("_id")
es.index(index='test_1',body=document,id=cnt)</pre>
3. 用 Dev Tool取得 mappings,看起來有一個 **pageCount**可以改 Interger,另外有嘗試調整 **publishedDate**但發生了一些問題,會在最後一題說明。
4. 基本上可以確定資料是可以進行寫入。
#### Stage 2. Batch Insert
1. 拿到 Notepad++檢視一下字元符號,得到訊息"} {"可能可以將document彼此隔開。
1. 將檔案讀入,用觀察到的 "} {"去分隔成為 list,檢視每個 Element,將括號補齊。
1. 根據時間複雜度,將跳脫字元 replace的步驟改放到開檔的時候做一次性處理,測試也沒問題。
1. 最後確認筆數與 **_id**的 Distinct Count是相同的,但是 **_id**在第400個 Document看起來像外部 Key的 Format,但在這邊因為有 pop掉原本的 id,另外補上一個 auto-increment的數字,所以暫時沒有探討。
1. 確認 json在 Python裡面可以成為 Dictionary物件之後,查看每個 Dictionary的 Keys都沒有下底線開頭所謂的 Metadata Field,資料面確認就到這邊。
1. 使用 Elasticsearch7的 API進行 POST,完成。
1. 從 Dev Tool GET Count數為431, Discovery檢視一下資料本身,看起來無異常。
1. 到 Stack Management產生 Index Pattern,因為 **publishedDate**的範圍太大,沒有特地加入 timestamp,接下來就開始使用資料視覺化。
#### Stage 3. Source **steam.games.json**
1. 由於這份資料不需要前處理就可以轉換成 Json,所以我這邊就直接 Load成 Dictionary,不過從資料上看來,他應該是一個回傳的 Payload,所以就先取 Respondes中的 Games的內容。
1. 觀察一個 Field **appid**其 Value是否為不可重複,將 appid串成 list,利用 list 轉 set之後,會消除重複值,比較 List跟 Set的 Length是否相同,確認都為192, Document也為相同筆數192,所以先用 appid暫時當作 id。
1. 將一筆資料 POST到 ES,確認 Mappings沒有太大問題,因為同樣 **_id**會自行增加一個 Version並且更新,所以就沒特別去刪除這一筆,就直接 Batch輸入,
1. 從 Dev Tool GET Count數為192, Discovery檢視一下,看起來無明顯異常。
1. 到 Stack Management產生 Index Pattern,開始使用資料視覺化。
## 4. The query you use to find out the total of flight delay
### ANS
```
GET kibana_sample_data_flights/_count
{
"query": {
"bool": {
"filter": [
{
"range": {
"FlightDelayMin": {
"gte": 1
}
}
}
]
}
}
}
```
## 5. What problem you facing during the entire practice and how you solve
### ANS
#### 無法在 Visualization選到 Integer類別的 Field
> * 我自己手動做了一些資料,在進行視覺化的時候遇到了這個問題,因為 Field Data Type怎麼改都沒有成功,我試著用 Discover觀察資料,發現多了一筆 Settings相關的資訊如下圖,檢視 Mappings覺得內容過於複雜,不太正常。
> 
> * 用動態產生 Mappings的方式直接建出 Index,比較兩者之後,確認原先的 Mappings是異常的,Field Data Type也不如我預期,這邊判斷 Settings不應該被視為一個 Document,而且看起來這個 Mappings是包了好幾層,所以推斷應該是整段 Create的 Command都被當成一個 Document PUSH進去。
> * 於是回頭確認官方文件,確定一件事, Create Index是用關鍵字 PUT,另外也測試 PUT是否可以針對 Type,答案是不可行,PUT到 Type層級也確定是找不到 Method的。
> * 這是原先錯誤的 Command。
```
POST /try_1/man
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
},
"mappings": {
"properties": {
"Name": { "type": "text" },
"Job": { "type": "text" },
"Age": { "type": "integer" },
"Gender": { "type": "text" }
}
}
}
# 更正後
PUT /try_1
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
},
"mappings": {
"properties": {
"Name": { "type": "text" },
"Job": { "type": "text" },
"Age": { "type": "integer" },
"Gender": { "type": "text" }
}
}
}
```
#### 承上,重塞資料的時候出現錯誤
```{
"error" : {
"root_cause" : [
{
"type" : "illegal_argument_exception",
"reason" : "Rejecting mapping update to [l2h_sample] as the final mapping would have more than 1 type: [_doc, man]"
}
],
"type" : "illegal_argument_exception",
"reason" : "Rejecting mapping update to [l2h_sample] as the final mapping would have more than 1 type: [_doc, man]"
},
"status" : 400
}
```
> 由於先前測試,指定了 Type的名稱,在 _search資料的時候遇到下面的 Error,想到課堂聽到 Type在不同版本有改特性,查找官網這版對於 Type的設定,結果, Type必須要 Single才會正常運作,而實際上 Default會給 **_doc**這樣的名稱,看 Youtube上一些外國人示範簡單的 Query也會在 GET的時候主動加上 **_doc**,所以將 Index刪除重新建立,讓 Type唯一。
#### 重新建立 Index,透過 Discover確認資料都正確無誤之後, Visualization還是選取不到 Integer類別的欄位
> 因為發現 Visualization能夠選擇用來 Aggregation的 Field還是跟之前一樣沒有變化,映像中設定 Index Pattern的時候,是一種預前宣告給 GUI用的動作,懷疑是這邊設定沒有更新,所以從 Stack Management裡面確認,跟 Console查詢得到的 Mappings結果不一樣,於是 Refresh Index Pattern解決這個問題。
#### 用 python內建的 json.loads去讀取一個 Document字串的時候,出現以下錯誤一
```
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
```
> 檢查 json的 Source Code確認他會對 File的文檔,用 Regular Expression,比對跟成對有關的規則,在這個時候就已經發生錯誤,原因是有雙引號或單引號不成對,這點用 Replace的方式加上跳脫符號處理。
```
_m=STRINGCHUNK.match,STRINGCHUNK = re.compile(r'(.*?)(["\\\x00-\x1f])', FLAGS))
```
#### 用 python內建的 json.loads去讀取一個 Document字串的時候,出現以下錯誤二
```
json.decoder.JSONDecodeError: Extra data: line 15 column 2 (char 2517)
```
> 將文檔貼到 Notepad++檢查 Char 2517,發現在用"} {" split文檔的時候,會缺大括弧,所以設定了一些頭尾判斷補齊。
#### 使用Python Elasticsearch API的時候, Port參數不存在
> 為了測試 API的基本功能,我先根據 IThome讀到的教學 Fork了一個 docker-compose在自己的 VM,先用 API直連預設的 9200 Port,但報錯,提示是不存在這個參數,尋找解答的時候,有文章提及 ES在新舊版差異很大,甚至在雲服務化後很多框架都有重新改版,我將 Error拿到 Stack Overflow,得到一些解答,高於7.14的 API都會跟我用的版本有不相容的問題,所以去檢查 pip3安裝的 API版本,看起來是最新的,果然不合用,使用 pip3降版,選擇跟 AWS Opensearch創建 Doamin時一樣的版本,7.10,測試連線成功,之後再改成連到 AWS,使用 URL跟一開始創建設定的帳號密碼進行當作引述進行明碼連線,成功取得 ES的訊息。
#### 在輸入 amazon.books.json資料時,時間格式的 Field報錯
```
elasticsearch.exceptions.RequestError: RequestError(400, 'mapper_parsing_exception', "failed to parse field [publishedDate.$date] of type [date] in document with id '-z-hDoEBMNMOjQaujx-d'. Preview of field's value: '2009-04-01T00:00:00.000-0700'")
```
> 因為想讓時間的 Format好看一點,所以在這個 Field加上了 Format yyyy-MM-dd並建立 Index,結果發生錯誤,研究官網,這個宣告,其實是一種 Parsing Rule,宣告之後就要照他的方式 Feed資料,測試了官方給的 Sample,他是用各種不同的 Format輸入到同一個 Index, 官方提供的 Mappings因為沒有對 date的 Parsing Rule設限,所以他示範的幾種格式都可以正常輸入到同一個 Index,也就是說,ES當你沒有設定 Parsing Rule的時候,他會動態解析 Data,然後在背後用相同的方式儲存。
```PUT my-index-000001
{
"mappings": {
"properties": {
"date": {
"type": "date",
"format": "yyyy-MM-dd" # 因為這個宣告導致 Parsing Rule被固定下來效果
}
}
}
}
```
#### 承上,重新建立 Index跟輸入資料之後,在 Visualization看不到資料
> Index Pattern建立的時候,因為把 publishedDate設定成 timestamp導致剛進入 Dashboad只有選擇最近的15分鐘,以至於看不到資料,因為過去有 Grafana的使用經驗,所以推斷是 Time Range影響到資料的呈現,從資料面檢視,發現書本出版跨的年度跨太多年,這樣 Time Ranger會選的非常大,所以取消 Timestamp,以方便這次的作業,但在 Flight的資料集有用到。