[{"data":1,"prerenderedAt":404},["ShallowReactive",2],{"portfolio-\u002Fportfolio\u002Ffranchise-realty-platform":3},{"id":4,"title":5,"award":6,"body":7,"cover":382,"description":367,"extension":383,"featured":384,"link":6,"meta":385,"navigation":386,"order":368,"path":387,"pinned":384,"repo":6,"role":388,"seo":389,"stack":390,"stem":400,"summary":401,"year":402,"__hash__":403},"portfolio\u002Fportfolio\u002Ffranchise-realty-platform.md","加盟房仲平台",null,{"type":8,"value":9,"toc":366},"minimark",[10,14,27,38,102,113,116,123,126,152,156,159,166,187,194,196,206,213,217,246,249,256,260,267,274,281,284,290,301,304,325,328],[11,12,13],"h2",{"id":13},"專案概述",[15,16,17,18,22,23,26],"p",{},"集團除了直營的主力品牌之外，旗下還有",[19,20,21],"strong",{},"多個加盟房仲品牌","，每個品牌都有自己的\n對外網站。這個專案由我獨立設計並開發，負責",[19,24,25],{},"所有加盟品牌網站","背後的平台：從\n資料同步、資料中台、搜尋，到各品牌的前端網站。",[15,28,29,30,33,34,37],{},"加盟品牌的物件資料，原本就是由各加盟店在集團的主力平台上建檔、維護，加盟網站要\n做的是把",[19,31,32],{},"屬於加盟品牌的物件","即時拿過來，再依品牌呈現在各自的網站上。所以整體\n架構和主力平台很像，最大的差別在於",[19,35,36],{},"資料來源","：",[39,40,41,56],"table",{},[42,43,44],"thead",{},[45,46,47,50,53],"tr",{},[48,49],"th",{},[48,51,52],{},"主力平台",[48,54,55],{},"加盟平台",[57,58,59,70,81,91],"tbody",{},[45,60,61,64,67],{},[62,63,36],"td",{},[62,65,66],{},"直接來自 MSSQL 原始資料",[62,68,69],{},"接收主力平台發布的物件事件",[45,71,72,75,78],{},[62,73,74],{},"資料範圍",[62,76,77],{},"直營物件",[62,79,80],{},"只挑出加盟品牌的物件",[45,82,83,86,89],{},[62,84,85],{},"查詢方式",[62,87,88],{},"買屋中台等資料中台 + Elasticsearch",[62,90,88],{},[45,92,93,96,99],{},[62,94,95],{},"對外網站",[62,97,98],{},"一個品牌",[62,100,101],{},"多個加盟品牌網站",[15,103,104,105,108,109,112],{},"這也是公司",[19,106,107],{},"第一個完全容器化的對外網站","，以及",[19,110,111],{},"第一個正式採用\nElasticsearch"," 的專案。",[11,114,115],{"id":115},"系統架構",[15,117,118],{},[119,120],"img",{"alt":121,"src":122},"加盟房仲平台架構圖：集團主力平台發布物件異動事件到 RabbitMQ，同步消費者只挑出加盟物件並轉成加盟用的資料格式，寫入 MSSQL 持久化、寫入 Elasticsearch 供查詢；加盟物件資料中台以 ASP.NET Core Web API 查詢 Elasticsearch，提供買屋搜尋、GEO 鄰近推薦與四大區推薦排序給各加盟品牌網站","\u002Fimages\u002Fportfolio\u002Ffranchise-realty-architecture.svg",[15,124,125],{},"整個平台分成三層：",[127,128,129,136,146],"ul",{},[130,131,132,135],"li",{},[19,133,134],{},"資料同步","：透過 RabbitMQ 接收主力平台的物件事件，挑出加盟物件後，同時寫入\n加盟專用的 MSSQL（持久化）與 Elasticsearch（查詢）",[130,137,138,141,142,145],{},[19,139,140],{},"資料中台","：以 ASP.NET Core Web API 實作的",[19,143,144],{},"加盟物件資料中台","，包含買屋中台\n等服務，所有查詢都走 Elasticsearch",[130,147,148,151],{},[19,149,150],{},"品牌網站","：各加盟品牌的前端網站，透過中台取得資料，只呈現屬於自己品牌的物件",[11,153,155],{"id":154},"資料同步從主力平台接收物件事件","資料同步：從主力平台接收物件事件",[15,157,158],{},"加盟物件在主力平台上建檔之後，加盟網站要「馬上」看得到；物件改價、下架，加盟網\n站也要同步反映。如果用排程定期去主力平台的資料庫撈資料，不只會有時間差，也會讓\n加盟平台和主力平台的資料庫綁死在一起。",[15,160,161,162,165],{},"所以改成",[19,163,164],{},"事件驅動","：主力平台在物件新增、修改、下架時發布事件到 RabbitMQ，加\n盟平台訂閱這些事件：",[167,168,169,175,181],"ol",{},[130,170,171,174],{},[19,172,173],{},"過濾","：收到事件後，先判斷這筆物件是否屬於加盟品牌，不是就直接略過",[130,176,177,180],{},[19,178,179],{},"轉換","：把主力平台的物件格式，轉成加盟平台需要的資料結構，並標上所屬的\n加盟品牌",[130,182,183,186],{},[19,184,185],{},"寫入","：同時寫入加盟專用的 MSSQL 與 Elasticsearch；下架事件則把物件從索引中\n移除",[15,188,189,190,193],{},"這樣的好處是兩個平台",[19,191,192],{},"只透過事件溝通","：主力平台不需要知道有哪些系統在接收它\n的事件，加盟平台也不需要讀主力平台的資料庫。日後主力平台內部怎麼改，只要事件\n格式不變，加盟平台都不受影響。",[11,195,144],{"id":144},[15,197,198,199,201,202,205],{},"和主力平台一樣，加盟平台也把查詢收斂到",[19,200,140],{},"，前端網站不直接碰資料庫。\n中台以 ASP.NET Core Web API 實作，包含",[19,203,204],{},"買屋中台","等服務，背後全部查詢加盟專用\n的 Elasticsearch。",[15,207,208,209,212],{},"所有加盟品牌共用同一套中台，查詢時帶上",[19,210,211],{},"品牌條件","，每個品牌網站就只會拿到自\n己的物件。新增一個加盟品牌時，不需要再複製一套後端，只要加上品牌的設定即可。",[214,215,216],"h3",{"id":216},"物件搜尋",[127,218,219,225,231],{},[130,220,221,224],{},[19,222,223],{},"關鍵字搜尋","：可以用區域、路名、社區名稱、捷運站等關鍵字找物件",[130,226,227,230],{},[19,228,229],{},"多條件篩選","：總價、坪數、房數、屋齡、物件類型等條件組合查詢",[130,232,233,236,237,241,242,245],{},[19,234,235],{},"GEO 鄰近物件推薦","：每筆物件建立索引時就把經緯度存成 ",[238,239,240],"code",{},"geo_point","，物件詳細頁\n以目前物件為中心，用 ",[238,243,244],{},"geo_distance"," 找出附近的其他物件並依距離排序",[214,247,248],{"id":248},"四大區推薦排序",[15,250,251,252,255],{},"首頁與推薦區塊的物件，依台灣",[19,253,254],{},"北、中、南、東四大區","計算並排序：使用者所在或正\n在瀏覽的區域，優先推薦同區的物件，再依序帶出其他區域。加盟店遍布全台，這樣能讓\n各地的使用者先看到離自己近、真正有機會去看屋的物件，而不是被單一區域的大量物件\n洗版。",[11,257,259],{"id":258},"前端angular-express","前端：Angular + Express",[15,261,262,263,266],{},"房仲網站非常依賴",[19,264,265],{},"搜尋引擎流量","，物件頁一定要能被 Google 正確收錄。原本的做法\n是 Angular 搭配 ASP.NET Core MVC 來處理 SEO，前後端技術混在一起，部署和維護都\n比較麻煩。",[15,268,269,270,273],{},"這次把前端改成 ",[19,271,272],{},"Angular + Express","：由 Express 負責在伺服器端渲染頁面，搜尋\n引擎拿到的是完整的 HTML，使用者進到頁面後再由 Angular 接手互動。前端與後端 API\n各自獨立，也各自打包成容器部署。",[15,275,276,277,280],{},"各加盟品牌的網站共用同一套前端架構，依品牌設定切換",[19,278,279],{},"配色、Logo 與版型","，品牌\n之間的差異集中在設定裡，不需要為每個品牌各維護一份程式碼。",[11,282,283],{"id":283},"容器化",[15,285,286,287,289],{},"這是公司",[19,288,107],{},"：前端（Angular + Express）、資料中台\n（ASP.NET Core）、同步消費者都各自打包成 Docker 映像部署。",[15,291,292,293,296,297,300],{},"當時公司其他網站都還跑在 IIS 上，並且依賴大量的",[19,294,295],{},"記憶體快取","撐住查詢流量，每\n個站台都吃掉大量記憶體。加盟平台因為查詢全部改走 Elasticsearch，",[19,298,299],{},"不需要在應\n用程式裡放記憶體快取","，服務本身是無狀態的，也才能順利容器化、隨流量增減實例。",[11,302,303],{"id":303},"成果",[127,305,306,313,316,319,322],{},[130,307,308,309,312],{},"一套平台支撐",[19,310,311],{},"集團所有加盟品牌網站","，新增品牌只需要加上設定",[130,314,315],{},"加盟物件透過事件即時同步，主力平台上架、改價、下架，加盟網站同步反映",[130,317,318],{},"公司第一個完全獨立開發、對外的容器化專案",[130,320,321],{},"公司第一個移除記憶體快取、解決 IIS 浪費大量記憶體資源問題的專案",[130,323,324],{},"公司第一個正式採用 Elasticsearch 的專案",[11,326,327],{"id":327},"使用技術",[127,329,330,336,342,354,360],{},[130,331,332,335],{},[19,333,334],{},"後端","：C#、ASP.NET Core Web API",[130,337,338,341],{},[19,339,340],{},"前端","：Angular、Express（伺服器端渲染）",[130,343,344,347,348,350,351,353],{},[19,345,346],{},"資料","：Elasticsearch（",[238,349,240],{},"、",[238,352,244],{},"）、MSSQL",[130,355,356,359],{},[19,357,358],{},"訊息","：RabbitMQ",[130,361,362,365],{},[19,363,364],{},"部署","：Docker",{"title":367,"searchDepth":368,"depth":368,"links":369},"",2,[370,371,372,373,378,379,380,381],{"id":13,"depth":368,"text":13},{"id":115,"depth":368,"text":115},{"id":154,"depth":368,"text":155},{"id":144,"depth":368,"text":144,"children":374},[375,377],{"id":216,"depth":376,"text":216},3,{"id":248,"depth":376,"text":248},{"id":258,"depth":368,"text":259},{"id":283,"depth":368,"text":283},{"id":303,"depth":368,"text":303},{"id":327,"depth":368,"text":327},"\u002Fimages\u002Fportfolio\u002Ffranchise-realty-cover.svg","md",false,{},true,"\u002Fportfolio\u002Ffranchise-realty-platform","獨立開發 ‧ 房仲業",{"title":5,"description":367},[391,392,393,394,395,396,397,398,399],"C#","ASP.NET Core","Angular","Express","RabbitMQ","Elasticsearch","Elasticsearch GEO","MSSQL","Docker","portfolio\u002Ffranchise-realty-platform","獨立開發集團旗下所有加盟房仲品牌的網站平台。架構與主力平台相同——由買屋中台等資料中台提供查詢、背後以 Elasticsearch 支撐關鍵字與 GEO 搜尋——差別在於資料來源：透過 RabbitMQ 即時接收主力平台的物件事件，挑出加盟物件同步進加盟專用的索引。是公司第一個完全容器化的對外網站，也是第一個採用 Elasticsearch 的專案。",2022,"pdce6vukbNYMQP73mXpgL4AEFqduOBZ8BWfndr7PTW8",1792959149968]