爬蟲系列之數據質量監控實踐篇:規則庫梳理與設計

先前在《爬蟲系列之數據質量監控(二):監控系統設計 》一文中,對採集中數據解析部分可能出現的各種異常,進行了大概的總結。比如:標題或內容中包含亂碼、css樣式、JavaScript代碼等。

由於出現的異常可能千奇百怪,我們不可能提前想到所有現象。此時,就需要根據目前已經發現的問題,總結出一套能夠靈活應對不同情況的規則庫。

其目的就是在數據持久化接口處,對接收的所有數據,依據信源系統中配置的規則進行校驗,以判斷採集到的數據的準確性,便與改進採集器或腳本,優化數據質量,提高產品的用戶體驗。

一. 規則庫必須是抽象的規則,而不是具體表象。

通過對《爬蟲系列之數據質量監控(二):監控系統設計》 中描述的各類規則進行抽象,大致可以總結出以下規則。

如下表所示:

序號	分類	規則細則
1	校驗規則	A字段值長度小於閥值A
2	校驗規則	A字段的值是否包含CSS樣式
3	校驗規則	A字段的值是否有亂碼
4	校驗規則	A字段值中漢字長度小於閥值A
5	校驗規則	A字段值是否符合yyyy-MM-dd HH:mm:ss時間格式
6	校驗規則	A字段值等於閥值A
7	校驗規則	A字段值大於閥值A
8	校驗規則	A字段值長度大於閥值A
9	校驗規則	A字段值長度等於閥值A
10	校驗規則	A字段的值是否包含JavaScript代碼
11	校驗規則	A字段值與字段B值相同
12	校驗規則	A字段值包括規則庫中配置閥值,或包括接口配置閥值A
13	校驗規則	A字段值以規則庫中配置閥值結尾,或以接口中閥值A結尾
14	校驗規則	A字段值是否包含日期
15	清洗規則	A字段值內容格式化
16	清洗規則	A字段值包含閥值A時,則刪除A字段值中閥值A字符串
17	清洗規則	A字段值包含閥值A字符時,直接丟棄
18	清洗規則	A字段值轉義字符還原
19	矯正規則	A字段時間大於B字段時間,則A字段值=B字段值
20	矯正規則	A字段值包含閥值A,則:B字段值=閥值B
21	矯正規則	A字段值包含閥值A,則A字段值中的閥值A替換爲閥值B

目前整理的上述14條數據質量校驗規則,基本上可以應對80%以上的異常。

至於清洗和矯正規則,則尚需要根據實際的業務規則,進行相應的補充。

二. 規則庫的邏輯實現

在抽象出相應的規則庫以後,需要根據規則庫的描述,進行後端編碼的邏輯現實,把文字描述用代碼進行實現。具體實現邏輯類似下述兩個規則:

1. 如規則1(A字段值長度小於閥值A)

代碼實現:

public Boolean isALengthLtB(MonitorRule mr, MonitorRuleRelation mrr,Object oneData) {
    //判斷A字段及A閥值不爲空
if (!StringUtils.isNotBlank(mrr.getInterAField())|| !StringUtils.isNotBlank(mrr.getThresholdA()))
        return false;
    Object aFieldValue = Reflect.getObjectXField(oneData, mrr.getInterAField());
//閥值A必須爲數字;
    if (!BooleanRegular.isNumber(mrr.getThresholdA())) 
        return false;
    //判斷字段A的值不爲空;
    if (!StringUtils.isNotBlank(aFieldValue)) return false;
    Double value = Double.parseDouble(mrr.getThresholdA());	
    if (aFieldValue.toString().length() < value.intValue()) 
        return true;
    return false;
}																								

使用場景:如判斷解析的標題或正文必須大於某個長度,否則認爲解析異常。

2. 如矯正規則19(A字段時間大於B字段時間,則A字段值=B字段值)

代碼實現:

public Object aGTb(MonitorRule mr, MonitorRuleRelation mrr, Object oneData) {
    if (!StringUtils.isNotBlank(mrr.getInterAField())|| !StringUtils.isNotBlank(mrr.getInterBField()))
            return oneData;
        Object a = Reflect.getObjectXField(oneData, mrr.getInterAField());
        Object b = Reflect.getObjectXField(oneData, mrr.getInterBField());
        if (!StringUtils.isNotBlank(a) || !StringUtils.isNotBlank(b)) // 不爲空
            return oneData;
        if (!BooleanRegular.isDate(a.toString())	|| !BooleanRegular.isDate(b.toString())) 
            return oneData;
// 必須是19位時間格式;
        if (a.toString().length() == 19 && b.toString().length() == 19) {
            long aLong = DateUtil.stringToLong(a.toString(),
                    DateUtil.year_month_day_hour_mines_seconds);
            long bLong = DateUtil.stringToLong(b.toString(),
                    DateUtil.year_month_day_hour_mines_seconds);
            if (aLong > bLong) {
                oneData = Reflect.setObjectXField(oneData,mrr.getInterAField(), b);
            }
        }
        return oneData;
    }

使用場景:如解析出的發佈時間大於採集時間,則使用採集時間填充發布時間

三. 規則庫與kafka統一接口的關係處理

規則庫最終是用在kafka統一接口處,以便對接收的數據進行校驗,找出異常情況。那麼,他們如何進行關聯呢?主要有以下兩步:

1. Kafka統一接口與ES索引庫進行關聯

由於kafka的每一個對外服務接口,均對應一個唯一的ES索引庫,所以接口接收的數據屬性字段,必須與索引庫一致。所以,在信源系統中的接口列表處,添加與ES索引對應屬性信息。如下圖客戶端接口的配置信息:

Kafka統一接口中,數據類型爲客戶端的數據推送接口如下:

APP.png

接口與ES索引對應的字段信息如下:

字段.png

2. 給接口字段添加校驗規則

比如需要給網站推送接口的標題字段添加清洗規則,則可以如下圖操作。

添加.png

或者添加矯正規則:

矯正.png

最終添加完畢以後如下圖所示: 效果.png

四. kafka統一接口的校驗處理

由於信源系統中已經配置了接口和規則庫之間的關係,其中二者是通過接口方法名稱和規則庫處理邏輯(規則庫處理邏輯:是規則庫後臺處理邏輯的方法名稱)進行關聯。如小圖所示:

關係.png

然後,在接口方法中通過類全路徑,以及規則處理邏輯方法名,通過反射的方式進行動態調用。這樣就可以根據字段配置的處理規則,靈活地進行各種規則的校驗。

具體處理的代碼類似下面:

import java.lang.reflect.Method;
import java.util.concurrent.Callable;
public class DynamicTask implements Callable<Object> {
// 該參數爲待調用的類名和方法名;格式:java.tools.executors.dynamic.TestClass.test2
    String classMethon;
    // 該參數爲爲調用classMethon方法需要傳入的參數集合 ;
    Object[] arguments; 
    /** 
     * @param classMethon
     *     類包.方法名。如:fy.java.tools.executors.dynamic.TestClass.test2(
     *     調用TestClass的test2方法)
     *     注意:classPackage包路徑中不能有'_'、'-'等特色字符,否則無法執行;
     * @param arguments 待調用方法需要的參數,參數順序必須和方法中的額參數順序相同;
     */
    public DynamicTask(String classMethon, Object[] arguments) {
        this.classMethon = classMethon;
        this.arguments = arguments;
    }
    public Object call() throws Exception {
        String classPackage = this.classMethon.substring(0, this.classMethon .lastIndexOf("."));// 類名
        String methodName = this.classMethon.substring(this.classMethon .lastIndexOf(".") + 1);// 方法名;
        Class<?> service = Class.forName(classPackage);
        Object result = null;
        Class<?>[] parameterTypes = null; // 獲得參數的類型
        try {
            Method[] methods = service.getMethods();
            for (Method method : methods) {
                String mName = method.getName();
                if (methodName.equals(mName)) {
                    parameterTypes = method.getParameterTypes();
                    break;
                }
            }
            /**
             * service是服務器端提供服務的對象,但是,要通過獲取到的調用方法的名稱,
             * 參數類型,以及參數來選擇對象的方法,並調用。獲得方法的名稱
             */
            try {
                // 通過反射機制獲得方法
                Method method = service.getMethod(methodName, parameterTypes); 
                // 通過反射機制獲得類的方法,並調用這個方法
                result = method.invoke(service.newInstance(), arguments); 
            } catch (Throwable e) {
                e.printStackTrace();
                System.out.println(arguments.toString());
            }
        } catch (Throwable e) { e.printStackTrace() ;}
        return result;
    }
}

上面就是數據質量校驗前後臺的大致處理邏輯,希望對各位有一定的參考意義。

更多內容請關注公衆號:十點數據。大家一起學習,一起進步。

相關閱讀

爬蟲系列之數據質量監控(一)

爬蟲系列之數據質量監控(二):監控系統設計

爬蟲系列之數據質量監控(三):kafka統一接口處理邏輯分析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章