vivo 應用商店推薦系統探索與實踐

介紹 vivo 應用商店推薦系統如何高效支撐個性化的推薦需求。算法

1、前言

商店的應用數據主要來源於運營排期、CPD、遊戲、算法等渠道,成立推薦項目以後也沒有變化,發生變化的是由推薦系統負責和數據源進行對接,商店服務端只須要和應用推薦系統進行對接便可。設計模式

若是讀者覺得咱們單純是把商店服務端代碼給照搬到推薦系統這邊來了那就真的是too young too simple 了,不作優化或者升級直接copy一個系統是不可能的,這輩子都不可能。如下我將介紹咱們如何去設計和規劃應用推薦系統的。架構

2、面臨的挑戰

在筆者眼中,商店應用推薦系統除了要具有高性能、高可用性及核心指標的監控能力以外,還有一個核心的能力就是高效支撐商店流量場景接入個性化推薦。框架

如何定義高效支撐?ide

  • 最起碼能支撐三四個並行的需求同時進行吧。
  • 一個需求開發週期最起碼不能超過2天吧。
  • bug少一點吧,平均下來每一個場景不該該超過2個吧。
  • 產品同窗的常態性的需求基本都能快速支持吧。

分享咱們一個應用推薦的策劃case看看:性能

在xx場景下,大數據

若是主應用A屬於應用類,優化

  • 則首先從從x1數據源去取Q1隊列。
  • 而後從x2數據源去取Q2隊列。
  • 而後用Q2隊列去截斷Q1隊列,交集以後進行同開發者過濾和一級分類過濾。
  • 若是交集爲空則用Q2去兜底,而後取交集隊列的n1和n2 位置上的元素做爲返回隊列。
  • 若是前面都沒有取到數據的話從大數據xxx表中按照主應用下應用點擊的機率取點擊率最高的分類下的n個,同時須要對這些數據進行隊列內的同開發者過濾。

若是主應用A屬於遊戲類,插件

  • 則xxxx
  • 進行二級分類過濾
  • 若是量不足的話,則從x(n)取數據而後進行處理,
  • 若是數據不足3個的話,須要從周榜單中取同一級分類下的應用按照下載排行進行兜底。

沒錯,讀者朋友不要懷疑本身,爲了避免把各位讀者大大繞暈,咱們這裏只是挑選了一個簡單的需求。實現這麼一個功能也沒有什麼大不了的,可是當這種個性化推薦需求有幾十個,後面還可能一致擴展下去的時候會不會內心發慌?來,簡單看下咱們如今個性化推薦的一部分需求,如圖(一)所示:線程

vivo 應用商店推薦系統探索與實踐

圖(一)

使用商店服務端以前的case by case的開發方案,不管如何都沒法實現上文中描述的要支撐商店高效接入推薦場景了,接着就是咱們如何去實現優化的過程了。

3、如何解決

爲了更好的說明解決思路,咱們從實際思考過程出發,一步步講解問題的解決過程。

3.1 業務流程抽象

單純從策劃上面來講,咱們每一個場景都須要至少作如圖(二)中的幾件事情:

vivo 應用商店推薦系統探索與實踐

圖(二)

  • 獲取推薦列表:調用各個數據源獲取的推薦隊列(須要注意的是不一樣場景下調用的接口並不一致,此外接口返回的字段和結構可能也不同)。
  • 隊列融合:將1中提到的進行交集或者並集並等操做。
  • 數據過濾(隊列內/隊列間):在隊列中進行各項過濾,過濾操做主要是爲了提高相關性。
  • 數據兜底:指在隊列數據不夠的時候,用榜單兜底,可能取周榜單數據的同一級分類數據,同二級分類數據。

筆者從開發便捷性出發,對模型進行了進一步的調整,調整後爲圖(三)

vivo 應用商店推薦系統探索與實踐

圖(三)

獲取隊列後對隊列進行安裝過濾和隊列內過濾(如主應用同開發者過濾等)能夠進行流程合併,主要有以下的緣由

  • 方便定義每個數據源的過濾策略,實際需求中不一樣的隊列也會使用不一樣的過濾策略。
  • 這種方式很是匹配模板設計模式,能確保咱們獲取推薦列表過程是一致和穩定的。

3.2 抽象流程延伸

到圖(三)這裏,讀者會發現咱們依然沒有可以解決咱們前面提到的各類推薦場景裏面的差別化過程。

其實在接觸幾個需求之後,咱們會發現,想要在一套代碼裏面去解決這麼大的差別性,幾乎不可能,或者即便實現了,那麼也會讓代碼變得無比複雜。與其這樣子,咱們還不如正視這種差別性,讓差別在場景插件裏面去實現,咱們花更多的精力去打理主幹。

那麼爲了支持讓場景可以具有靈活的擴展能力,筆者在基於圖(三)的基礎上增長了四個環節:

  • 隊列結果線程內共享:使用ThreadLocal來實現。存儲各推薦隊列的結果主要是爲了便於後續使用某推薦隊列作填充的需求,另外就是避免須要再重複請求三方數據接口,減小接口重複調用。
  • 插件隊列兜底:主要目的是在過濾後在數量不足需求的狀況下,使用指定的隊列完成填充,場景插件亦可按需填寫實現填充邏輯,實現隊列內容的補充。
  • 插件接口回調:該環節主要是對前面的隊列作個性化的處理,如對隊列進行干預等,沒有將插件接口回調和插件隊列兜底融合在一塊兒主要緣由是插件隊列融合能夠實現可配置化的設置。
  • 周榜單兜底:提供通用的周榜單數據查詢能力,支持按照各類維度進行查詢,此部分數據做爲隊列的最後兜底。

拓展後的流程圖如圖(四)所示

vivo 應用商店推薦系統探索與實踐

圖(四)

3.3 總體邏輯框圖

通過上述的分析可知,咱們能夠儘量的把個性化的場景內容放在插件層實現,框架層負責加載按場景加載場景插件的具體個性化推薦邏輯。

系統從分層思路上講從上至下共分爲:插件層,框架層,協議適配層,數據源服務層,原子服務層,基礎服務層,上層經過 SDK 依賴下層的服務(接口),各層次職責爲:

  • 插件層:各個場景對應的插件,框架層對插件回調或者擴展接口提供默認實現,插件層按需實現具體的邏輯。
  • 框架層:定義推薦數據的核心流程和執行邏輯,回調插件層的實現的擴展和回調接口。
  • 協議適配層:負責按照場景找到場景對應的數據源服務,並封裝轉換協議和進行數據轉換。
  • 數據源服務層:與各個隊列提供方提供的RPC服務封裝層。
  • 原子服務層:過濾類型的相關服務,主要是依賴於商店的 RPC 服務,使用組合的設計模式,服務能夠進行組合。
  • 基礎服務層:支持從開發者、一級分類、二級分類、應用類型等緯度進行相關性的判斷或者過濾,同原子服務層同樣,此層服務也是原子粒度,支持進行組合控制。

vivo 應用商店推薦系統探索與實踐

至此,相信你們都知曉了,針對於個性化的推薦,咱們的開發工做最終將聚焦於開發場景插件,不須要再額外開發每個業務流程了。

應用推薦系統架構

vivo 應用商店推薦系統探索與實踐

3.4 關鍵實現

在完成第三步總體邏輯框圖設計以後,咱們從場景參數定義,服務設計原則,設計模式使用,場景熱插拔等方面進行了相關的方案研究並最終實現了方案的落地。

3.4.1 場景服務參數定義

爲實現推薦場景足夠通用,咱們將數據源層,原子服務層,基礎服務層的內容進行了服務配置的映射,經過在配置中定義對應的配置項來實現服務的映射和組合,針對於差別性的內容在插件層進行實現。以以下的配置項示意圖來講明:

  • sourceMap:場景服務定義爲map用於支持場景下多個模塊或者實驗組的情形,其中key爲模塊ID,商店服務端請求推薦的時候,須要攜帶此參數。
  • cpdRequest 、algorithmRequest 、gameRequest:用於定義對應的RPC調用的請求參數。
  • filterRequest:用於定義隊列內的過濾請求,如主應用同開發者過濾等。
  • unionStrategy:定義隊列合併和融合及隊列間的合併規則。
  • supplement:兜底策略;
  • sourceList:使用的數據源,如上圖中定義了兩個數據源,則表示在此場景下須要從兩個數據源獲取數據,而後進行隊列合併及後處理。

vivo 應用商店推薦系統探索與實踐

3.4.2 服務原子化與惟一化

實現服務原子化與服務惟一化對本系統相當重要,在實現過程當中是嚴格遵守以下兩點來:

應用推薦依賴的三方RPC服務及內部的一些過濾邏輯都封裝成了細粒度的原子服務(方法)的SDK。SDK中的內容不包含個性化推薦場景的具體業務性的能力,體現的重點是基礎功能項,業務內容須要在場景插件中進行實現,統一類型的服務儘量支持組合。

服務惟一化在對於實現系統的收斂和代碼規模可控相當重要,咱們也是不斷的在朝着這個努力。各服務層都是以SDK的形式對外提供相關的功能,在SDK中實現服務調用入口的惟一性。

3.4.3 合理使用設計模式

系統中使用了較多的設計模式來優化總體架構,以下重點來介紹使用的模板設計模式、策略模式及組合模式:

在獲取推薦原始隊列中使用了模板設計模式和策略模式來實現此過程。

使用模板設計模式的好處顯而易見,可以容易促進此部分處理邏輯流程化。

針對不一樣的數據源,須要使用不一樣的數據源服務和方法,使用策略模式的好處是便於定義在不一樣場景下對不一樣的接口的調用。

同類型的原子服務或者方法儘量支持組合模式,這種會爲後續的擴展提供很大的便利性。

以實際的實現方法來講明,在咱們定義過濾類型的時候,支持傳入多個過濾類型,上層業務在使用的時候按需傳入便可。使用組合的設計模式在提高擴展性方面起到了巨大的做用。

3.4.4 場景的熱插拔

系統中爲實現場景之間的隔離和互不干擾,筆者使用了Java SPI的方式,在框架層定義了場景接口,接口實現類則在各個場景在獨自的Jar中實現。這種方式有助於插件程序對框架層和基礎服務層的侵入性降到最低。

4、帶來的改變

之前商店服務端在各個接口的service層寫完整的推薦隊列獲取、融合、組裝、過濾邏輯,有大量的重複內容,且隨着版本的不斷迭代,有不少版本不一樣的處理邏輯夾雜在一塊兒,致使改造難升級難,牽一髮動全身。目前應用推薦系統在兩個方向帶來較大改善:

  1. 流程框架的邏輯徹底抽象並獨立,各個業務場景只須要按需寫不多的插件回調邏輯便可,(不涉及十分特殊的場景可徹底不用寫插件回調擴展,經過配置對應的場景規則配置便可,可徹底實現免開發,目前有30%左右的場景免開發)。
  2. 場景之間徹底隔離和獨立, 涉及複雜的功能升級可經過升級對應的場景id或者模塊id來作增量實現,不影響現有邏輯。

5、寫在最後

經過上述相關的方案落地,針對於各個推薦場景,咱們大概減小了75%的開發工做量,同時bug率也獲得大幅度的下降。

做者:vivo-Huang Xiaoqun

相關文章
相關標籤/搜索