av激情亚洲男人的天堂国语,日韩欧美精品一中文字幕,无码av一区二区三区无码,国产又色又爽又刺激的a片,国产又色又爽又刺激的a片

如何設(shè)計一個易擴(kuò)展、易運(yùn)維的內(nèi)容下發(fā)服務(wù)架構(gòu)?

重要術(shù)語解釋

  1. 內(nèi)容 :包括商品、圖文、視頻等,服務(wù)端通過算法推薦,最終下發(fā)給客戶端消費的內(nèi)容
  2. 補(bǔ)齊數(shù)據(jù)源 :對于內(nèi)容id,提供一個或多個維度的關(guān)聯(lián)信息
  3. 內(nèi)容補(bǔ)齊 :獲取到內(nèi)容id后,請求不同補(bǔ)齊數(shù)據(jù)源,獲取內(nèi)容周邊素材,用于客戶端展示

常見服務(wù)分類

作者在阿里做過和學(xué)習(xí)過不少服務(wù)實現(xiàn),如下,給阿里服務(wù)體系中常見服務(wù)大致分一個類,每個類別有些是應(yīng)用層,有些是中間層,這里不作贅述,這里我們重點討論內(nèi)容型服務(wù)

主要關(guān)注點

比如對于我們淘系業(yè)務(wù),搭建一套服務(wù),我們需要先想清楚下面的幾個點

  1. 內(nèi)容來源:從算法、運(yùn)營配置或者其他渠道來,唯一標(biāo)識內(nèi)容id的key向量是哪些,基于這些id,如何進(jìn)行相關(guān)內(nèi)容補(bǔ)齊
  2. 內(nèi)容約束:算法推薦比較穩(wěn)定,但是運(yùn)營配置的內(nèi)容,可能會過期,不能滿足客戶端展示需求,我們需要保證內(nèi)容完整性,校驗內(nèi)容的一致性
  3. 內(nèi)容運(yùn)維:內(nèi)容下發(fā)服務(wù)上線后,業(yè)務(wù)會不斷變化,內(nèi)容篩選條件的增減,客戶端也在不斷迭代,接口設(shè)計需要考慮靈活性

常見問題及解決方案

面臨問題

  1. 各種字段需要補(bǔ)齊 :不同字段來源于不同數(shù)據(jù)源,容易出現(xiàn)面條式代碼,需要靈活的架構(gòu)來處理這種復(fù)雜度
  2. 不同場景對于下發(fā)字段的校驗要求不同 :需要基于標(biāo)注的Validator模塊來處理字段粒度判斷
  3. 運(yùn)營和產(chǎn)品的需求經(jīng)常變化 :對于tab排序、篩選條件,接口設(shè)計要考慮擴(kuò)展性,提供運(yùn)營能力

解決方案

構(gòu)建一套pipeline,每個處理節(jié)點關(guān)注一個問題解決

  1. Datasource :數(shù)據(jù)來源(算法推薦、數(shù)據(jù)庫、緩存、運(yùn)營配置、置頂數(shù)據(jù))。方法名:fromXXX
  2. Transfer :類型轉(zhuǎn)換。方法名:toXXX
  3. Filter :數(shù)據(jù)過濾(黑白名單,字段約束)。方法名:byXXX
  4. Sorter :數(shù)據(jù)排序。方法名:topXXX、shuffleXXX
  5. Completer :補(bǔ)數(shù)據(jù)。方法名:addXXX
  6. Validator :有效性驗證,過濾不符合要求的數(shù)據(jù),比如商品某個字段缺失。方法名:checkXXX
  7. Factory :基于基本元素,數(shù)據(jù)拼接生產(chǎn)。方法名:createXXX
  8. Iterator :保存各類遍歷過程

是不是看起來有點類似Java8中stream的API,但這套pipeline具體還是偏內(nèi)容下發(fā)業(yè)務(wù),比Java原生API要更豐富,以淘寶的AR淘業(yè)務(wù)為例,pipeline如下:

代碼實現(xiàn)效果

下面代碼實現(xiàn)一套基于運(yùn)營配置數(shù)據(jù)源的pipeline

1.首先,自定義Pipeline,沒有使用Lambada,對java7及以下也適用

public class PipeLine {
private List> functionList = new ArrayList<>();
public PipeLine add(PipeLineFunction pipeLineFunction) {
functionList.add(pipeLineFunction);
return this;
}
public D execute(D data, C context) throws Exception {
for (PipeLineFunction function : functionList) {
data = (D) function.execute(data, context);
}
return data;
}
}

2.其次管線,對于處理次序和節(jié)點進(jìn)行指定:包括從配置讀取數(shù)據(jù)--->通過arType過濾--->隨機(jī)打亂數(shù)據(jù)--->置頂主題類數(shù)據(jù)--->翻頁--->增加sku和item信息--->增加AR模型信息--->完整性校驗

public void initSkuResultHotRecommendPipeLine() {
PipeLine skuResultHotRecommendPipeLine = new PipeLine();
skuResultHotRecommendPipeLine
.add((data, context) -> skuResultDataSource.fromConfig(context))
.add((data, context) -> skuResultSorter.shuffle(data))
.add((data, context) -> skuResultSorter.topTheme(data, context))
.add((data, context) -> skuResultSorter.page(data, context))
.add((data, context) -> skuResultCompleter.addSkuInfo(data))
.add((data, context) -> skuResultCompleter.addAREffect(data, context))
.add((data, context) -> skuResultValidator.check(data));
}

3.最后,搭建pipeline,接口收到請求后,通過管線處理,下發(fā)對應(yīng)內(nèi)容

public ResultVO getSkuList(SkuQuery skuQuery) {
try {
SkuResultVO skuResultVO = skuResultHotRecommendPipeLine
.execute(new SkuResultVO(), skuQuery);
} catch (Exception e) {
log.error("", e.fillInStackTrace());
return ResultVO.failOf(e.getMessage());
}
return ResultVO.failOf(CameraArCause.No_Valid_Ar_Type
.toMessage(skuQuery.toString()));
}

4.我們再討論一下對于有固定的遍歷邏輯的情況,遍歷方式也可以抽象成一個iterator,在不同的filter作為參數(shù)傳入下,完成遍歷功能,下圖就是對商品的一種遍歷,這個特性用到FunctionalInterface標(biāo)注,需要java8及以上

(1) 定義遍歷器

@FunctionalInterface
public interface FilterFunction {
boolean execute(T t) throws Exception;
}
@FunctionalInterface
public interface IterateFunction {
T execute(T t, FilterFunction filterFunction);
}

private IterateFunction skuVOFilterIterator = (skuResultVO, filter) -> {
List skuFeedUnitVOList = skuResultVO.getSkuFeedUnitVOList()
.stream().filter(skuFeedUnitVO -> {
List filterSkuVOList = skuFeedUnitVO.getSkuVOList()
.stream().filter(skuVO -> {
try {
return filter.execute(skuVO);
} catch (Exception e) {
log.warn("", e);
return false;
}
}).collect(toList());
if (filterSkuVOList.size() == 0) {
return false;
}
skuFeedUnitVO.setSkuVOList(filterSkuVOList);
return true;
}).collect(toList());
if (skuFeedUnitVOList.size() == 0) {
log.warn(CameraArCause.No_Valid_Sku_Feed_Unit_List
.toMessage(skuResultVO.toString()));
}
skuResultVO.setSkuFeedUnitVOList(skuFeedUnitVOList);
return skuResultVO;
};

(2) 在Filter模塊中使用遍歷器,如果把skuResultVO換成一個返回SkuResultVO的Supplier,是不是有點柯里化的味道啦?

public SkuResultVO byArType(SkuResultVO skuResultVO) {
return skuResultIterator.getSkuVOFilterIterator()
.execute(skuResultVO, (FilterFunction) skuVO ->
!CameraArSwitch.Black_List_Config.getArType()
.contains(skuVO.getArType()));
}

整體架構(gòu)

  1. API & View層:為各類客戶端、服務(wù)端提供接口
  2. Controller層:不同來源的調(diào)用適配,權(quán)限控制
  3. Manager層:每個接口pipeline的各個節(jié)點實現(xiàn)、二方和三方包封裝
  4. Middleware層:集團(tuán)常見中間件
  5. Model層:按照阿里Java規(guī)范的各個層級POJO
  6. Common層:自研公共組件,主要是切面類、native命令執(zhí)行類等

Tips

淘系商品信息補(bǔ)全

對于補(bǔ)齊數(shù)據(jù)源的選擇,要詳細(xì)了解上游各個補(bǔ)齊數(shù)據(jù)源的業(yè)務(wù)定位和業(yè)務(wù)邊界,選擇合適的補(bǔ)齊數(shù)據(jù)源。比如淘系商品補(bǔ)全數(shù)據(jù)源常見服務(wù)有以下幾個,要根據(jù)業(yè)務(wù)自身需求

數(shù)據(jù)補(bǔ)齊二方服務(wù)

優(yōu)勢

劣勢

商品中心(IC)

最底層的數(shù)據(jù)源,有item和sku維度的信息

維度不夠多,比如一些商品的運(yùn)營信息

阿拉丁

維度比較多,比如商品白底圖

只有item維度信息,但是有些數(shù)據(jù)源不穩(wěn)定,比如品牌信息有些商品會缺失

搜索的Summary

跟主搜的信息保持一致,信息比較實時,比如優(yōu)惠、銷量信息

只有item維度信息,維度不夠多

篩選能力

內(nèi)容下發(fā)除了做好個性化,如果是一個公域產(chǎn)品,對內(nèi)容的篩選能力決定用戶是否能主動找到自己想要的商品,我們需要設(shè)計一個易擴(kuò)展的篩選器接口,常見的垂直頻道類產(chǎn)品,一級和二級tab頁就滿足業(yè)務(wù)訴求,但對應(yīng)比較大的公域,比如搜索,需要支持多維度篩選+多篩選能力,都需要實現(xiàn)兩個接口,這時, 我們需要設(shè)計一個通用的接口格式,做好兩件事。

  1. 下發(fā)篩選器
  2. 上傳用戶選擇的篩選項
  • 一級和二級tab頁

只需要下發(fā)一級和二級的tab樹狀接口即可,用戶通過先后選擇一級和二級tab來過濾內(nèi)容,這里不作過多的討論。

  • 多維度篩選器

需要下發(fā)多維度篩選器,如果有一級Tab,多維度篩選器放在每個Tab內(nèi)部,例子如下:

1.篩選器下發(fā)接口,格式如下,其中Name結(jié)尾的字段為前端展示,Id結(jié)尾的字段作為篩選上傳的接口字段

{
"tabList": [
{
"tabName": "tab1",
"tabId": "xxx",
"filterList": [
{
"filterName": "xxx",
"filterId": "xxx",
"filterItemList": [
{
"filterItemName": "fitler1",
"filterItemId": "xxx"
},
{
"filterItemName": "fitler2",
"filterItemId": "xxx"
}
]
}
]
},
{
"tabName": "tab2",
"tabId": "xxx",
"filterList": [
{
"filterName": "xxx",
"filterId": "xxx",
"filterItemList": [
{
"filterItemName": "fitler1",
"filterItemId": "xxx"
},
{
"filterItemName": "fitler2",
"filterItemId": "xxx"
}
]
}
]
}
]
}

2.上傳用戶選擇的篩選項,接口格式如下,tabId可以作為單獨的字段傳,filterList是另外一個字段

{
"tabId": "xxx",
"filterList": [
{
"filterId": "xxx",
"filterItemList": [
{
"filterItemId": "xxx"
},
{
"filterItemId": "xxx"
}
]
},
{
"filterId": "xxx",
"filterItemList": [
{
"filterItemId": "xxx"
},
{
"filterItemId": "xxx"
}
]
}
]
}

總結(jié)和展望

總結(jié)

本文通過大淘寶業(yè)務(wù)的例子,梳理出一套 內(nèi)容服務(wù)下發(fā)內(nèi)容時面臨的問題和挑戰(zhàn)、設(shè)計一套內(nèi)容處理鏈路,用模塊化的設(shè)計來控制系統(tǒng)的復(fù)雜度,并且對接口上線后,如何靈活運(yùn)維進(jìn)行了討論,重點研究了保證易擴(kuò)展、易運(yùn)維的思路,希望對各位有所啟發(fā)。

展望

內(nèi)容下發(fā)服務(wù)已經(jīng)有些團(tuán)隊推出了前后端一體的方案,客戶端不用請求應(yīng)用服務(wù)來拿商品數(shù)據(jù),通過統(tǒng)一的平臺接口,把客戶端布局和內(nèi)容填充一起請求來返回,這么做的好處是效率比較高,迭代起來快,帶來的不便是客戶端和平臺耦合比較緊,靈活性變差,比如客戶端有一塊內(nèi)容源不走平臺,就會比較麻煩


網(wǎng)站題目:如何設(shè)計一個易擴(kuò)展、易運(yùn)維的內(nèi)容下發(fā)服務(wù)架構(gòu)?
網(wǎng)站URL:http://uogjgqi.cn/article/dpcisie.html
掃二維碼與項目經(jīng)理溝通

我們在微信上24小時期待你的聲音

解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流