[{"data":1,"prerenderedAt":1553},["ShallowReactive",2],{"article-\u002Farticles\u002Felasticsearch-getting-started":3},{"id":4,"title":5,"body":6,"date":1539,"description":1540,"excerpt":1541,"extension":1542,"meta":1543,"navigation":1544,"path":1545,"seo":1546,"stem":1547,"tags":1548,"__hash__":1552},"articles\u002Farticles\u002Felasticsearch-getting-started.md","Elasticsearch 入門：從 RDBMS 概念對照到 Query DSL 與 Aggregation 實戰",{"type":7,"value":8,"toc":1517},"minimark",[9,36,41,101,105,108,113,116,146,150,153,271,274,278,281,331,335,338,360,381,385,388,550,553,628,631,710,714,736,820,828,843,847,862,870,936,942,946,960,1050,1054,1068,1072,1075,1151,1174,1178,1199,1319,1336,1340,1345,1440,1451,1454,1469,1472,1476,1479,1482,1513],[10,11,12,13,18,19,23,24,28,29,35],"p",{},"這篇是從實際專案（",[14,15,17],"a",{"href":16},"\u002Fportfolio\u002Frealty-platform-rebuild","房仲平台核心系統重構","、\n",[14,20,22],{"href":21},"\u002Fportfolio\u002Ffranchise-realty-platform","加盟房仲平台"," 等）用 Elasticsearch 支\n撐物件搜尋的經驗整理出來的入門教學，不求涵蓋所有官方文件的細節，而是把剛接觸\nElasticsearch 時最容易卡住的幾個概念，用關聯式資料庫（RDBMS）的角度對照講清\n楚。完整範例查詢與 ",[25,26,27],"code",{},"docker-compose"," 環境放在\n",[14,30,34],{"href":31,"rel":32},"https:\u002F\u002Fgithub.com\u002Ftom3019\u002FHappyElasticSearch",[33],"nofollow","HappyElasticSearch","。",[37,38,40],"h2",{"id":39},"先建立心智模型elasticsearch-對應-rdbms-的什麼","先建立心智模型：Elasticsearch 對應 RDBMS 的什麼",[42,43,44,57],"table",{},[45,46,47],"thead",{},[48,49,50,54],"tr",{},[51,52,53],"th",{},"RDBMS",[51,55,56],{},"Elasticsearch",[58,59,60,69,77,85,93],"tbody",{},[48,61,62,66],{},[63,64,65],"td",{},"Table",[63,67,68],{},"Index",[48,70,71,74],{},[63,72,73],{},"Row",[63,75,76],{},"Document",[48,78,79,82],{},[63,80,81],{},"Column",[63,83,84],{},"Field",[48,86,87,90],{},[63,88,89],{},"Schema",[63,91,92],{},"Mapping",[48,94,95,98],{},[63,96,97],{},"SQL",[63,99,100],{},"DSL（Query DSL，用 JSON 表示查詢）",[37,102,104],{"id":103},"mapping定義欄位型別","Mapping：定義欄位型別",[10,106,107],{},"Mapping 定義 Document 裡每個欄位的型別，等同於在 RDBMS 定義 Table 的欄位型\n別。",[109,110,112],"h3",{"id":111},"dynamic-mapping動態映射","Dynamic Mapping（動態映射）",[10,114,115],{},"Elasticsearch 預設是動態映射：只要新增 Document 進 Index，就會依資料值自動\n推斷欄位型別，不需要事先定義。",[10,117,118,122,123,126,127,130,131,133,134,136,137,140,141,143,144,35],{},[119,120,121],"strong",{},"要注意的地方","：字串欄位經過 Dynamic Mapping 後，預設會同時產生 ",[25,124,125],{},"text"," 與\n",[25,128,129],{},"keyword"," 兩個子欄位——",[25,132,125],{}," 用於全文檢索（會被斷詞），",[25,135,129],{}," 用於精確比\n對與排序、聚合（不斷詞）。這代表",[119,138,139],{},"同一個字串值會被存兩份","。如果某個欄位你確\n定只會拿來做精確比對（例如關鍵字標籤），讓它預設同時保留 ",[25,142,125],{}," 反而浪費儲存\n空間，應該用 Dynamic Mapping Template 或 Explicit Mapping 把它限定成只有\n",[25,145,129],{},[109,147,149],{"id":148},"explicit-mapping明確映射","Explicit Mapping（明確映射）",[10,151,152],{},"想完全自己控制型別時，可以在建立 Index 時就宣告 Mapping：",[154,155,160],"pre",{"className":156,"code":157,"language":158,"meta":159,"style":159},"language-json shiki shiki-themes github-dark","PUT \u002FindexName\n{\n  \"mappings\": {\n    \"properties\": {\n      \"name\":     { \"type\": \"text\" },\n      \"account\":  { \"type\": \"text\" },\n      \"password\": { \"type\": \"keyword\" }\n    }\n  }\n}\n","json","",[25,161,162,171,177,187,195,217,234,253,259,265],{"__ignoreMap":159},[163,164,167],"span",{"class":165,"line":166},"line",1,[163,168,170],{"class":169},"s95oV","PUT \u002FindexName\n",[163,172,174],{"class":165,"line":173},2,[163,175,176],{"class":169},"{\n",[163,178,180,184],{"class":165,"line":179},3,[163,181,183],{"class":182},"sDLfK","  \"mappings\"",[163,185,186],{"class":169},": {\n",[163,188,190,193],{"class":165,"line":189},4,[163,191,192],{"class":182},"    \"properties\"",[163,194,186],{"class":169},[163,196,198,201,204,207,210,214],{"class":165,"line":197},5,[163,199,200],{"class":182},"      \"name\"",[163,202,203],{"class":169},":     { ",[163,205,206],{"class":182},"\"type\"",[163,208,209],{"class":169},": ",[163,211,213],{"class":212},"sU2Wk","\"text\"",[163,215,216],{"class":169}," },\n",[163,218,220,223,226,228,230,232],{"class":165,"line":219},6,[163,221,222],{"class":182},"      \"account\"",[163,224,225],{"class":169},":  { ",[163,227,206],{"class":182},[163,229,209],{"class":169},[163,231,213],{"class":212},[163,233,216],{"class":169},[163,235,237,240,243,245,247,250],{"class":165,"line":236},7,[163,238,239],{"class":182},"      \"password\"",[163,241,242],{"class":169},": { ",[163,244,206],{"class":182},[163,246,209],{"class":169},[163,248,249],{"class":212},"\"keyword\"",[163,251,252],{"class":169}," }\n",[163,254,256],{"class":165,"line":255},8,[163,257,258],{"class":169},"    }\n",[163,260,262],{"class":165,"line":261},9,[163,263,264],{"class":169},"  }\n",[163,266,268],{"class":165,"line":267},10,[163,269,270],{"class":169},"}\n",[10,272,273],{},"也可以先建 Index 再補上映射；但既有欄位的型別一旦寫入資料就無法直接改，只能\n重建 Index 或用 Reindex API 遷移。",[37,275,277],{"id":276},"查詢結果的欄位怎麼看response-結構","查詢結果的欄位怎麼看（Response 結構）",[10,279,280],{},"一次查詢的回應大致長這樣，理解這幾個欄位對讀查詢結果很關鍵：",[282,283,284,291,301,307,313,319,325],"ul",{},[285,286,287,290],"li",{},[25,288,289],{},"hits.total.value","：符合查詢條件的資料總數",[285,292,293,296,297,300],{},[25,294,295],{},"hits.total.relation","：",[25,298,299],{},"eq"," 表示 total 是精確值（沒有被截斷估算）",[285,302,303,306],{},[25,304,305],{},"hits.max_score","：整次查詢中最高的匹配分數",[285,308,309,312],{},[25,310,311],{},"hits.hits[]._index","：資料所在的 Index",[285,314,315,318],{},[25,316,317],{},"hits.hits[]._id","：Document 的 ID",[285,320,321,324],{},[25,322,323],{},"hits.hits[]._score","：這筆資料的匹配分數，分數越高代表跟查詢條件越相關",[285,326,327,330],{},[25,328,329],{},"hits.hits[]._source","：實際的資料內容",[37,332,334],{"id":333},"query-dsl兩種查詢情境","Query DSL：兩種查詢情境",[10,336,337],{},"Elasticsearch 的查詢分成兩種 Context，效能特性完全不同：",[282,339,340,350],{},[285,341,342,345,346,349],{},[119,343,344],{},"Query Context","：會計算匹配分數（",[25,347,348],{},"_score","），分數越高排序越前面；子查詢\n結果與分數會被快取",[285,351,352,355,356,359],{},[119,353,354],{},"Filter Context","：只回答「符合或不符合」，",[119,357,358],{},"不計算分數","，處理速度更\n快，也不快取有相關性算分的查詢",[361,362,363],"blockquote",{},[10,364,365,366,369,370,373,374,18,377,380],{},"⚠️ 效能建議：不需要排序相關性的條件（例如「狀態是否為上架中」「日期是否在\n某個範圍」）優先用 ",[25,367,368],{},"filter"," 而不是 ",[25,371,372],{},"must","；也盡量避免用 ",[25,375,376],{},"Script",[25,378,379],{},"Wildcard","，這兩種查詢方式很容易吃滿效能。",[109,382,384],{"id":383},"boolean-query複合查詢","Boolean Query（複合查詢）",[10,386,387],{},"如同 RDBMS 的多條件組合查詢：",[154,389,391],{"className":156,"code":390,"language":158,"meta":159,"style":159},"GET \u002Fkibana_sample_data_ecommerce\u002F_search\n{\n  \"query\": {\n    \"bool\": {\n      \"must\": [\n        { \"term\": { \"order_date\": { \"value\": \"2022-02-03\" } } },\n        { \"term\": { \"day_of_week\": { \"value\": \"Thursday\" } } }\n      ],\n      \"should\": [\n        { \"term\": { \"customer_id\": { \"value\": 26 } } },\n        { \"term\": { \"customer_id\": { \"value\": 27 } } }\n      ]\n    }\n  }\n}\n",[25,392,393,398,402,409,416,424,450,473,478,485,507,529,535,540,545],{"__ignoreMap":159},[163,394,395],{"class":165,"line":166},[163,396,397],{"class":169},"GET \u002Fkibana_sample_data_ecommerce\u002F_search\n",[163,399,400],{"class":165,"line":173},[163,401,176],{"class":169},[163,403,404,407],{"class":165,"line":179},[163,405,406],{"class":182},"  \"query\"",[163,408,186],{"class":169},[163,410,411,414],{"class":165,"line":189},[163,412,413],{"class":182},"    \"bool\"",[163,415,186],{"class":169},[163,417,418,421],{"class":165,"line":197},[163,419,420],{"class":182},"      \"must\"",[163,422,423],{"class":169},": [\n",[163,425,426,429,432,434,437,439,442,444,447],{"class":165,"line":219},[163,427,428],{"class":169},"        { ",[163,430,431],{"class":182},"\"term\"",[163,433,242],{"class":169},[163,435,436],{"class":182},"\"order_date\"",[163,438,242],{"class":169},[163,440,441],{"class":182},"\"value\"",[163,443,209],{"class":169},[163,445,446],{"class":212},"\"2022-02-03\"",[163,448,449],{"class":169}," } } },\n",[163,451,452,454,456,458,461,463,465,467,470],{"class":165,"line":236},[163,453,428],{"class":169},[163,455,431],{"class":182},[163,457,242],{"class":169},[163,459,460],{"class":182},"\"day_of_week\"",[163,462,242],{"class":169},[163,464,441],{"class":182},[163,466,209],{"class":169},[163,468,469],{"class":212},"\"Thursday\"",[163,471,472],{"class":169}," } } }\n",[163,474,475],{"class":165,"line":255},[163,476,477],{"class":169},"      ],\n",[163,479,480,483],{"class":165,"line":261},[163,481,482],{"class":182},"      \"should\"",[163,484,423],{"class":169},[163,486,487,489,491,493,496,498,500,502,505],{"class":165,"line":267},[163,488,428],{"class":169},[163,490,431],{"class":182},[163,492,242],{"class":169},[163,494,495],{"class":182},"\"customer_id\"",[163,497,242],{"class":169},[163,499,441],{"class":182},[163,501,209],{"class":169},[163,503,504],{"class":182},"26",[163,506,449],{"class":169},[163,508,510,512,514,516,518,520,522,524,527],{"class":165,"line":509},11,[163,511,428],{"class":169},[163,513,431],{"class":182},[163,515,242],{"class":169},[163,517,495],{"class":182},[163,519,242],{"class":169},[163,521,441],{"class":182},[163,523,209],{"class":169},[163,525,526],{"class":182},"27",[163,528,472],{"class":169},[163,530,532],{"class":165,"line":531},12,[163,533,534],{"class":169},"      ]\n",[163,536,538],{"class":165,"line":537},13,[163,539,258],{"class":169},[163,541,543],{"class":165,"line":542},14,[163,544,264],{"class":169},[163,546,548],{"class":165,"line":547},15,[163,549,270],{"class":169},[10,551,552],{},"對應的 SQL 概念大致是：",[154,554,558],{"className":555,"code":556,"language":557,"meta":159,"style":159},"language-sql shiki shiki-themes github-dark","SELECT * FROM TABLE\nWHERE order_date = '2022-02-03'\n  AND day_of_week = 'Thursday'\n  AND (customer_id = 26 OR customer_id = 27)\n","sql",[25,559,560,575,589,602],{"__ignoreMap":159},[163,561,562,566,569,572],{"class":165,"line":166},[163,563,565],{"class":564},"snl16","SELECT",[163,567,568],{"class":564}," *",[163,570,571],{"class":564}," FROM",[163,573,574],{"class":564}," TABLE\n",[163,576,577,580,583,586],{"class":165,"line":173},[163,578,579],{"class":564},"WHERE",[163,581,582],{"class":169}," order_date ",[163,584,585],{"class":564},"=",[163,587,588],{"class":212}," '2022-02-03'\n",[163,590,591,594,597,599],{"class":165,"line":179},[163,592,593],{"class":564},"  AND",[163,595,596],{"class":169}," day_of_week ",[163,598,585],{"class":564},[163,600,601],{"class":212}," 'Thursday'\n",[163,603,604,606,609,611,614,617,620,622,625],{"class":165,"line":189},[163,605,593],{"class":564},[163,607,608],{"class":169}," (customer_id ",[163,610,585],{"class":564},[163,612,613],{"class":182}," 26",[163,615,616],{"class":564}," OR",[163,618,619],{"class":169}," customer_id ",[163,621,585],{"class":564},[163,623,624],{"class":182}," 27",[163,626,627],{"class":169},")\n",[10,629,630],{},"四種子句的角色：",[42,632,633,646],{},[45,634,635],{},[48,636,637,640,643],{},[51,638,639],{},"子句",[51,641,642],{},"作用",[51,644,645],{},"對應邏輯",[58,647,648,663,680,695],{},[48,649,650,654,657],{},[63,651,652],{},[25,653,372],{},[63,655,656],{},"必須符合，會計算分數",[63,658,659,660],{},"相當於 ",[25,661,662],{},"AND",[48,664,665,669,675],{},[63,666,667],{},[25,668,368],{},[63,670,671,672,674],{},"必須符合，",[119,673,358],{},"，速度較快",[63,676,659,677,679],{},[25,678,662],{},"，建議優先使用",[48,681,682,687,690],{},[63,683,684],{},[25,685,686],{},"should",[63,688,689],{},"符合會加分，非必要條件",[63,691,659,692],{},[25,693,694],{},"OR",[48,696,697,702,705],{},[63,698,699],{},[25,700,701],{},"must_not",[63,703,704],{},"必須不符合",[63,706,659,707],{},[25,708,709],{},"NOT",[109,711,713],{"id":712},"全文檢索full-text-queries","全文檢索（Full Text Queries）",[10,715,716,721,722,725,726,728,729,731,732,735],{},[119,717,718],{},[25,719,720],{},"match","：標準的全文查詢，支援 ",[25,723,724],{},"operator","（",[25,727,662],{},"／",[25,730,694],{},"）與 ",[25,733,734],{},"fuzziness","\n（模糊比對，容忍拼字誤差）：",[154,737,739],{"className":156,"code":738,"language":158,"meta":159,"style":159},"GET \u002Fkibana_sample_data_ecommerce\u002F_search\n{\n  \"query\": {\n    \"match\": {\n      \"customer_id\": {\n        \"query\": 27,\n        \"operator\": \"and\",\n        \"fuzziness\": \"AUTO\"\n      }\n    }\n  }\n}\n",[25,740,741,745,749,755,762,769,781,793,803,808,812,816],{"__ignoreMap":159},[163,742,743],{"class":165,"line":166},[163,744,397],{"class":169},[163,746,747],{"class":165,"line":173},[163,748,176],{"class":169},[163,750,751,753],{"class":165,"line":179},[163,752,406],{"class":182},[163,754,186],{"class":169},[163,756,757,760],{"class":165,"line":189},[163,758,759],{"class":182},"    \"match\"",[163,761,186],{"class":169},[163,763,764,767],{"class":165,"line":197},[163,765,766],{"class":182},"      \"customer_id\"",[163,768,186],{"class":169},[163,770,771,774,776,778],{"class":165,"line":219},[163,772,773],{"class":182},"        \"query\"",[163,775,209],{"class":169},[163,777,526],{"class":182},[163,779,780],{"class":169},",\n",[163,782,783,786,788,791],{"class":165,"line":236},[163,784,785],{"class":182},"        \"operator\"",[163,787,209],{"class":169},[163,789,790],{"class":212},"\"and\"",[163,792,780],{"class":169},[163,794,795,798,800],{"class":165,"line":255},[163,796,797],{"class":182},"        \"fuzziness\"",[163,799,209],{"class":169},[163,801,802],{"class":212},"\"AUTO\"\n",[163,804,805],{"class":165,"line":261},[163,806,807],{"class":169},"      }\n",[163,809,810],{"class":165,"line":267},[163,811,258],{"class":169},[163,813,814],{"class":165,"line":509},[163,815,264],{"class":169},[163,817,818],{"class":165,"line":531},[163,819,270],{"class":169},[10,821,822,827],{},[119,823,824],{},[25,825,826],{},"multi_match","：同一個查詢值同時比對多個欄位，很適合「搜尋框」這種不知道\n使用者要查哪個欄位的場景。",[10,829,830,835,836,728,839,842],{},[119,831,832],{},[25,833,834],{},"match_all","：查詢全部資料，務必搭配 ",[25,837,838],{},"size",[25,840,841],{},"from"," 分頁使用，避免一次把\n整個 Index 撈出來。",[109,844,846],{"id":845},"欄位等級查詢term-level-queries","欄位等級查詢（Term-level Queries）",[10,848,849,858,859,861],{},[119,850,851,854,855],{},[25,852,853],{},"term"," \u002F ",[25,856,857],{},"terms","：精確比對單一或多個值（不做全文分詞），適合查\n",[25,860,129],{},"、數字、日期這類欄位。",[10,863,864,869],{},[119,865,866],{},[25,867,868],{},"range","：範圍查詢：",[154,871,873],{"className":156,"code":872,"language":158,"meta":159,"style":159},"GET \u002Fkibana_sample_data_ecommerce\u002F_search\n{\n  \"query\": {\n    \"range\": {\n      \"order_date\": { \"gte\": \"2022-01-01\", \"lte\": \"2022-01-31\" }\n    }\n  }\n}\n",[25,874,875,879,883,889,896,924,928,932],{"__ignoreMap":159},[163,876,877],{"class":165,"line":166},[163,878,397],{"class":169},[163,880,881],{"class":165,"line":173},[163,882,176],{"class":169},[163,884,885,887],{"class":165,"line":179},[163,886,406],{"class":182},[163,888,186],{"class":169},[163,890,891,894],{"class":165,"line":189},[163,892,893],{"class":182},"    \"range\"",[163,895,186],{"class":169},[163,897,898,901,903,906,908,911,914,917,919,922],{"class":165,"line":197},[163,899,900],{"class":182},"      \"order_date\"",[163,902,242],{"class":169},[163,904,905],{"class":182},"\"gte\"",[163,907,209],{"class":169},[163,909,910],{"class":212},"\"2022-01-01\"",[163,912,913],{"class":169},", ",[163,915,916],{"class":182},"\"lte\"",[163,918,209],{"class":169},[163,920,921],{"class":212},"\"2022-01-31\"",[163,923,252],{"class":169},[163,925,926],{"class":165,"line":219},[163,927,258],{"class":169},[163,929,930],{"class":165,"line":236},[163,931,264],{"class":169},[163,933,934],{"class":165,"line":255},[163,935,270],{"class":169},[10,937,938,939,35],{},"對應 SQL：",[25,940,941],{},"WHERE order_date BETWEEN '2022-01-01' AND '2022-01-31'",[109,943,945],{"id":944},"只要欄位不要全部資料","只要欄位，不要全部資料",[10,947,948,949,952,953,728,956,959],{},"用 ",[25,950,951],{},"_source"," 的 ",[25,954,955],{},"includes",[25,957,958],{},"excludes"," 控制回傳欄位，減少不必要的網路傳輸：",[154,961,963],{"className":156,"code":962,"language":158,"meta":159,"style":159},"GET \u002Fkibana_sample_data_ecommerce\u002F_search\n{\n  \"size\": 20,\n  \"from\": 0,\n  \"query\": {},\n  \"_source\": {\n    \"excludes\": [\"order_id\", \"order_date\"],\n    \"includes\": [\"*\"]\n  }\n}\n",[25,964,965,969,973,985,997,1004,1011,1029,1042,1046],{"__ignoreMap":159},[163,966,967],{"class":165,"line":166},[163,968,397],{"class":169},[163,970,971],{"class":165,"line":173},[163,972,176],{"class":169},[163,974,975,978,980,983],{"class":165,"line":179},[163,976,977],{"class":182},"  \"size\"",[163,979,209],{"class":169},[163,981,982],{"class":182},"20",[163,984,780],{"class":169},[163,986,987,990,992,995],{"class":165,"line":189},[163,988,989],{"class":182},"  \"from\"",[163,991,209],{"class":169},[163,993,994],{"class":182},"0",[163,996,780],{"class":169},[163,998,999,1001],{"class":165,"line":197},[163,1000,406],{"class":182},[163,1002,1003],{"class":169},": {},\n",[163,1005,1006,1009],{"class":165,"line":219},[163,1007,1008],{"class":182},"  \"_source\"",[163,1010,186],{"class":169},[163,1012,1013,1016,1019,1022,1024,1026],{"class":165,"line":236},[163,1014,1015],{"class":182},"    \"excludes\"",[163,1017,1018],{"class":169},": [",[163,1020,1021],{"class":212},"\"order_id\"",[163,1023,913],{"class":169},[163,1025,436],{"class":212},[163,1027,1028],{"class":169},"],\n",[163,1030,1031,1034,1036,1039],{"class":165,"line":255},[163,1032,1033],{"class":182},"    \"includes\"",[163,1035,1018],{"class":169},[163,1037,1038],{"class":212},"\"*\"",[163,1040,1041],{"class":169},"]\n",[163,1043,1044],{"class":165,"line":261},[163,1045,264],{"class":169},[163,1047,1048],{"class":165,"line":267},[163,1049,270],{"class":169},[37,1051,1053],{"id":1052},"aggregationes-版的-group-by-與統計函式","Aggregation：ES 版的 GROUP BY 與統計函式",[10,1055,1056,1057,1060,1061,1060,1064,1067],{},"Aggregation 提供類似 RDBMS ",[25,1058,1059],{},"GROUP BY","、",[25,1062,1063],{},"COUNT",[25,1065,1066],{},"AVG"," 的能力，分成三種：",[109,1069,1071],{"id":1070},"bucket-aggregation分桶相當於-group-by","Bucket Aggregation：分桶（相當於 GROUP BY）",[10,1073,1074],{},"依欄位值把 Document 分到不同的桶：",[154,1076,1078],{"className":156,"code":1077,"language":158,"meta":159,"style":159},"GET \u002FIndexName\u002F_search\n{\n  \"size\": 0,\n  \"aggs\": {\n    \"day\": {\n      \"terms\": { \"field\": \"day_of_week\", \"size\": 10 }\n    }\n  }\n}\n",[25,1079,1080,1085,1089,1099,1106,1113,1139,1143,1147],{"__ignoreMap":159},[163,1081,1082],{"class":165,"line":166},[163,1083,1084],{"class":169},"GET \u002FIndexName\u002F_search\n",[163,1086,1087],{"class":165,"line":173},[163,1088,176],{"class":169},[163,1090,1091,1093,1095,1097],{"class":165,"line":179},[163,1092,977],{"class":182},[163,1094,209],{"class":169},[163,1096,994],{"class":182},[163,1098,780],{"class":169},[163,1100,1101,1104],{"class":165,"line":189},[163,1102,1103],{"class":182},"  \"aggs\"",[163,1105,186],{"class":169},[163,1107,1108,1111],{"class":165,"line":197},[163,1109,1110],{"class":182},"    \"day\"",[163,1112,186],{"class":169},[163,1114,1115,1118,1120,1123,1125,1127,1129,1132,1134,1137],{"class":165,"line":219},[163,1116,1117],{"class":182},"      \"terms\"",[163,1119,242],{"class":169},[163,1121,1122],{"class":182},"\"field\"",[163,1124,209],{"class":169},[163,1126,460],{"class":212},[163,1128,913],{"class":169},[163,1130,1131],{"class":182},"\"size\"",[163,1133,209],{"class":169},[163,1135,1136],{"class":182},"10",[163,1138,252],{"class":169},[163,1140,1141],{"class":165,"line":236},[163,1142,258],{"class":169},[163,1144,1145],{"class":165,"line":255},[163,1146,264],{"class":169},[163,1148,1149],{"class":165,"line":261},[163,1150,270],{"class":169},[10,1152,1153,1154,1157,1158,1161,1162,1165,1166,1169,1170,1173],{},"回傳結果會依 ",[25,1155,1156],{},"day_of_week"," 分組，每組附上該值出現的次數（",[25,1159,1160],{},"doc_count","），例如\n",[25,1163,1164],{},"\"key\": \"Thursday\", \"doc_count\": 775","。這裡的 ",[25,1167,1168],{},"\"size\": 0"," 代表",[119,1171,1172],{},"不要回傳原\n始查詢命中的資料","，只要聚合結果——查詢結果本身用不到時，這樣可以省掉大量不\n必要的資料傳輸。",[109,1175,1177],{"id":1176},"metric-aggregation數學運算","Metric Aggregation：數學運算",[10,1179,1180,728,1183,728,1186,728,1189,728,1192,1195,1196,296],{},[25,1181,1182],{},"min",[25,1184,1185],{},"max",[25,1187,1188],{},"avg",[25,1190,1191],{},"sum",[25,1193,1194],{},"cardinality","，或是一次拿到全部統計值的\n",[25,1197,1198],{},"stats",[154,1200,1202],{"className":156,"code":1201,"language":158,"meta":159,"style":159},"GET \u002FIndexName\u002F_search\n{\n  \"size\": 0,\n  \"aggs\": {\n    \"productsBaseAvg\": { \"avg\": { \"field\": \"products.base_price\" } },\n    \"productsBaseMax\": { \"max\": { \"field\": \"products.base_price\" } },\n    \"productsBaseMin\": { \"min\": { \"field\": \"products.base_price\" } },\n    \"productsBaseStats\": { \"stats\": { \"field\": \"products.base_price\" } }\n  }\n}\n",[25,1203,1204,1208,1212,1222,1228,1250,1270,1290,1311,1315],{"__ignoreMap":159},[163,1205,1206],{"class":165,"line":166},[163,1207,1084],{"class":169},[163,1209,1210],{"class":165,"line":173},[163,1211,176],{"class":169},[163,1213,1214,1216,1218,1220],{"class":165,"line":179},[163,1215,977],{"class":182},[163,1217,209],{"class":169},[163,1219,994],{"class":182},[163,1221,780],{"class":169},[163,1223,1224,1226],{"class":165,"line":189},[163,1225,1103],{"class":182},[163,1227,186],{"class":169},[163,1229,1230,1233,1235,1238,1240,1242,1244,1247],{"class":165,"line":197},[163,1231,1232],{"class":182},"    \"productsBaseAvg\"",[163,1234,242],{"class":169},[163,1236,1237],{"class":182},"\"avg\"",[163,1239,242],{"class":169},[163,1241,1122],{"class":182},[163,1243,209],{"class":169},[163,1245,1246],{"class":212},"\"products.base_price\"",[163,1248,1249],{"class":169}," } },\n",[163,1251,1252,1255,1257,1260,1262,1264,1266,1268],{"class":165,"line":219},[163,1253,1254],{"class":182},"    \"productsBaseMax\"",[163,1256,242],{"class":169},[163,1258,1259],{"class":182},"\"max\"",[163,1261,242],{"class":169},[163,1263,1122],{"class":182},[163,1265,209],{"class":169},[163,1267,1246],{"class":212},[163,1269,1249],{"class":169},[163,1271,1272,1275,1277,1280,1282,1284,1286,1288],{"class":165,"line":236},[163,1273,1274],{"class":182},"    \"productsBaseMin\"",[163,1276,242],{"class":169},[163,1278,1279],{"class":182},"\"min\"",[163,1281,242],{"class":169},[163,1283,1122],{"class":182},[163,1285,209],{"class":169},[163,1287,1246],{"class":212},[163,1289,1249],{"class":169},[163,1291,1292,1295,1297,1300,1302,1304,1306,1308],{"class":165,"line":255},[163,1293,1294],{"class":182},"    \"productsBaseStats\"",[163,1296,242],{"class":169},[163,1298,1299],{"class":182},"\"stats\"",[163,1301,242],{"class":169},[163,1303,1122],{"class":182},[163,1305,209],{"class":169},[163,1307,1246],{"class":212},[163,1309,1310],{"class":169}," } }\n",[163,1312,1313],{"class":165,"line":261},[163,1314,264],{"class":169},[163,1316,1317],{"class":165,"line":267},[163,1318,270],{"class":169},[10,1320,1321,1323,1324,728,1327,728,1329,728,1331,728,1333,1335],{},[25,1322,1198],{}," 一次回傳 ",[25,1325,1326],{},"count",[25,1328,1182],{},[25,1330,1185],{},[25,1332,1188],{},[25,1334,1191],{},"，不用分開寫四個聚合。",[109,1337,1339],{"id":1338},"pipeline-aggregation對聚合結果再聚合巢狀分組","Pipeline Aggregation：對聚合結果再聚合（巢狀分組）",[10,1341,1342,1343,296],{},"在一個 Bucket Aggregation 裡面再放一個 Bucket Aggregation，達到多層分組，\n相當於 RDBMS 多欄位的 ",[25,1344,1059],{},[154,1346,1348],{"className":156,"code":1347,"language":158,"meta":159,"style":159},"GET \u002FIndexName\u002F_search\n{\n  \"size\": 0,\n  \"aggs\": {\n    \"county\": {\n      \"terms\": { \"field\": \"county.keyword\" },\n      \"aggs\": {\n        \"city\": { \"terms\": { \"field\": \"district.keyword\" } }\n      }\n    }\n  }\n}\n",[25,1349,1350,1354,1358,1368,1374,1381,1396,1403,1424,1428,1432,1436],{"__ignoreMap":159},[163,1351,1352],{"class":165,"line":166},[163,1353,1084],{"class":169},[163,1355,1356],{"class":165,"line":173},[163,1357,176],{"class":169},[163,1359,1360,1362,1364,1366],{"class":165,"line":179},[163,1361,977],{"class":182},[163,1363,209],{"class":169},[163,1365,994],{"class":182},[163,1367,780],{"class":169},[163,1369,1370,1372],{"class":165,"line":189},[163,1371,1103],{"class":182},[163,1373,186],{"class":169},[163,1375,1376,1379],{"class":165,"line":197},[163,1377,1378],{"class":182},"    \"county\"",[163,1380,186],{"class":169},[163,1382,1383,1385,1387,1389,1391,1394],{"class":165,"line":219},[163,1384,1117],{"class":182},[163,1386,242],{"class":169},[163,1388,1122],{"class":182},[163,1390,209],{"class":169},[163,1392,1393],{"class":212},"\"county.keyword\"",[163,1395,216],{"class":169},[163,1397,1398,1401],{"class":165,"line":236},[163,1399,1400],{"class":182},"      \"aggs\"",[163,1402,186],{"class":169},[163,1404,1405,1408,1410,1413,1415,1417,1419,1422],{"class":165,"line":255},[163,1406,1407],{"class":182},"        \"city\"",[163,1409,242],{"class":169},[163,1411,1412],{"class":182},"\"terms\"",[163,1414,242],{"class":169},[163,1416,1122],{"class":182},[163,1418,209],{"class":169},[163,1420,1421],{"class":212},"\"district.keyword\"",[163,1423,1310],{"class":169},[163,1425,1426],{"class":165,"line":261},[163,1427,807],{"class":169},[163,1429,1430],{"class":165,"line":267},[163,1431,258],{"class":169},[163,1433,1434],{"class":165,"line":509},[163,1435,264],{"class":169},[163,1437,1438],{"class":165,"line":531},[163,1439,270],{"class":169},[10,1441,1442,1443,1446,1447,1450],{},"結果會先依 ",[25,1444,1445],{},"county","（縣市）分組，每個縣市底下再依 ",[25,1448,1449],{},"district","（行政區）分\n組——像是「台北市 → 大安區、內湖區」「新北市 → 板橋區、新莊區」這樣的階層統\n計。",[37,1452,1453],{"id":1453},"本機環境",[154,1455,1459],{"className":1456,"code":1457,"language":1458,"meta":159,"style":159},"language-shell shiki shiki-themes github-dark","docker-compose up\n","shell",[25,1460,1461],{"__ignoreMap":159},[163,1462,1463,1466],{"class":165,"line":166},[163,1464,27],{"class":1465},"svObZ",[163,1467,1468],{"class":212}," up\n",[10,1470,1471],{},"會啟動對應版本的 Elasticsearch 與 Kibana，直接在 Kibana 的 Dev Tools 貼上面\n的查詢範例就能跑。",[37,1473,1475],{"id":1474},"延伸在-aspnet-core-中使用","延伸：在 ASP.NET Core 中使用",[10,1477,1478],{},"倉庫裡也附了一個分層（Application／Service／Repository）的 ASP.NET Core 範\n例專案，示範怎麼把上面的查詢邏輯包裝進一般後端服務的架構裡，而不是散落在各處\n直接寫死 DSL 字串。",[37,1480,1481],{"id":1481},"總結",[282,1483,1484,1487,1498,1507],{},[285,1485,1486],{},"把 Mapping／Document／Index 對應回 Schema／Row／Table，能少走很多彎路",[285,1488,1489,1490,1492,1493,1495,1496],{},"字串欄位預設會存兩份（",[25,1491,125],{}," + ",[25,1494,129],{},"），確定只需要精確比對時就該用\nExplicit Mapping 限定成 ",[25,1497,129],{},[285,1499,1500,1501,1503,1504,1506],{},"不需要算分數的條件優先用 ",[25,1502,368],{},"，效能比 ",[25,1505,372],{}," 好",[285,1508,1509,1510,1512],{},"只要聚合結果、不需要原始資料時，",[25,1511,1168],{}," 能省下大量不必要的傳輸",[1514,1515,1516],"style",{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}",{"title":159,"searchDepth":173,"depth":173,"links":1518},[1519,1520,1524,1525,1531,1536,1537,1538],{"id":39,"depth":173,"text":40},{"id":103,"depth":173,"text":104,"children":1521},[1522,1523],{"id":111,"depth":179,"text":112},{"id":148,"depth":179,"text":149},{"id":276,"depth":173,"text":277},{"id":333,"depth":173,"text":334,"children":1526},[1527,1528,1529,1530],{"id":383,"depth":179,"text":384},{"id":712,"depth":179,"text":713},{"id":845,"depth":179,"text":846},{"id":944,"depth":179,"text":945},{"id":1052,"depth":173,"text":1053,"children":1532},[1533,1534,1535],{"id":1070,"depth":179,"text":1071},{"id":1176,"depth":179,"text":1177},{"id":1338,"depth":179,"text":1339},{"id":1453,"depth":173,"text":1453},{"id":1474,"depth":173,"text":1475},{"id":1481,"depth":173,"text":1481},"2022-03-18","這篇是從實際專案（房仲平台核心系統重構、\n加盟房仲平台 等）用 Elasticsearch 支\n撐物件搜尋的經驗整理出來的入門教學，不求涵蓋所有官方文件的細節，而是把剛接觸\nElasticsearch 時最容易卡住的幾個概念，用關聯式資料庫（RDBMS）的角度對照講清\n楚。完整範例查詢與 docker-compose 環境放在\nHappyElasticSearch。",null,"md",{},true,"\u002Farticles\u002Felasticsearch-getting-started",{"title":5,"description":1540},"articles\u002Felasticsearch-getting-started",[56,1549,1550,1551],"Kibana","NoSQL","資料庫","hf86G5jsCEg7KwDnt-tOEtYK_BtP1Bkt0udh5O34MPE",1792959150574]