ETL-Kettle學(xué)習(xí)筆記(入門,簡(jiǎn)介,簡(jiǎn)單操作)

Kettle:簡(jiǎn)介

ETL:簡(jiǎn)介
ETL(Extract-Transform-Load的縮寫,即數(shù)據(jù)抽取、轉(zhuǎn)換、裝載的過(guò)程),對(duì)于企業(yè)或行業(yè)應(yīng)用來(lái)說(shuō),我們經(jīng)常會(huì)遇到各種數(shù)據(jù)的處理,轉(zhuǎn)換,遷移,所以了解并掌握一種etl工具的使用,必不可少的,Kettle就是強(qiáng)大的ETL工具。

Kettle:概念

Kettle是一款國(guó)外開(kāi)源的ETL工具,純java編寫,可以在Window、Linux、Unix上運(yùn)行,綠色無(wú)需安裝,數(shù)據(jù)抽取高效穩(wěn)定。

Kettle 中文名稱叫水壺,該項(xiàng)目的主程序員MATT 希望把各種數(shù)據(jù)放到一個(gè)壺里,然后以一種指定的格式流出。

Kettle這個(gè)ETL工具集,它允許你管理來(lái)自不同數(shù)據(jù)庫(kù)的數(shù)據(jù),通過(guò)提供一個(gè)圖形化的用戶環(huán)境來(lái)描述你想做什么,而不是你想怎么做。

Kettle中有兩種腳本文件,transformation(.ktr)和job(.kjb),transformation完成針對(duì)數(shù)據(jù)的基礎(chǔ)轉(zhuǎn)換,job則完成整個(gè)工作流的控制。

Kettle:四大家族(核心組件)

Chef(中文:廚師)、Kitchen(中文:廚房)、Spoon(中文:勺子)、Pan(中文:平底鍋)

Chef—工作(job)設(shè)計(jì)工具 (GUI方式)。

Kitchen—工作(job)執(zhí)行器 (命令行方式)。

Spoon—轉(zhuǎn)換(transform)設(shè)計(jì)工具 (GUI方式)。

pan—轉(zhuǎn)換(transform)執(zhí)行器 (命令行方式)。

Job和Transformation的差別:Transformation專注于數(shù)據(jù)的ETL,而Job的范圍比較廣,可以是Transformation,也可以是Mail、SQL、Shell、FTP等,甚至可以是另外一個(gè)Job。

image
Kettle:概念模型
image

Kettle的執(zhí)行分為兩個(gè)層次:Job和Transformation。這兩個(gè)層次的最主要的在于數(shù)據(jù)的傳遞和運(yùn)行方式

1.Transformation:定義對(duì)數(shù)據(jù)操作的容器,數(shù)據(jù)操作就是數(shù)據(jù)從輸入到輸出的一個(gè)過(guò)程,可以理解為比Job粒度更小一級(jí)的容器,我們將任務(wù)分解成Job,然后需要將Job分解成一個(gè)或多個(gè)Transformation,每個(gè)Transformation只完成一部分工作。

(定義對(duì)數(shù)據(jù)操作的容器,數(shù)據(jù)操作就是數(shù)據(jù)從輸入到輸出的一個(gè)過(guò)程,可以理解為比作業(yè)粒度更小一級(jí)的容器,我們將任務(wù)分解成作業(yè),然后需要將作業(yè)分解成一個(gè)或多個(gè)轉(zhuǎn)換,每個(gè)轉(zhuǎn)換只完成一部分工作。


2.Step:是Transformation內(nèi)部的最小單元,每一個(gè)Step完成一個(gè)特定的功能。
3.Job:負(fù)責(zé)將Transformation組織在一起進(jìn)而完成某一工作,通常我們需要把一個(gè)大的任務(wù)分解成幾個(gè)邏輯上隔離的Job,當(dāng)這幾個(gè)Job都完成了,也就說(shuō)明這項(xiàng)任務(wù)完成了。

(負(fù)責(zé)將[轉(zhuǎn)換]組織在一起進(jìn)而完成某一塊工作,通常我們需要把一個(gè)大的任務(wù)分解成幾個(gè)邏輯上隔離的作業(yè),當(dāng)這幾個(gè)作業(yè)都完成了,也就說(shuō)明這項(xiàng)任務(wù)完成了。

4.Job Entry:Job Entry是Job內(nèi)部的執(zhí)行單元,每一個(gè)Job Entry用于實(shí)現(xiàn)特定的功能,如:驗(yàn)證表是否存在,發(fā)送郵件等。可以通過(guò)Job來(lái)執(zhí)行另一個(gè)Job或者Transformation,也就是說(shuō)Transformation和Job都可以作為Job Entry。
5.Hop:用于在Transformation中連接Step,或者在Job中連接Job Entry,是一個(gè)數(shù)據(jù)流的圖形化表示。

在Kettle中Job中的JobEntry是串行執(zhí)行的,故Job中必須有一個(gè)Start的JobEntry;Transformation中的Step是并行執(zhí)行的。

Kettle:目錄文件

image
![image](https://upload-images.jianshu.io/upload_images/11576306-a8384ebc52b87c88.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
image
image

Kettle:部署

安裝JDK:

由于Kettle是由java語(yǔ)言開(kāi)發(fā),該軟件的允許需要java運(yùn)行環(huán)境的依賴,需要先安裝好JDK,準(zhǔn)備好運(yùn)行環(huán)境。

配置環(huán)境變量:

JAVA_HOME:JDK的安裝目錄

KETTLE_HOME:kettle的解壓目錄

image
image

Kettle:圖形界面

image

Kettle:核心概念

可視化編程:

Kettle可以被歸類為可視化編程語(yǔ)言(Visula Programming Languages),因?yàn)镵ettle因?yàn)榭梢允褂脠D形化的方式定義復(fù)雜的ETL程序和工作流。

Kettle 里的圖就是轉(zhuǎn)換和作業(yè)

可視化編程一直是Kettle的核心概念,它可以快速構(gòu)建復(fù)雜的ETL作業(yè)和減低維護(hù)工作量。它是通過(guò)隱藏很多技術(shù)細(xì)節(jié),使IT領(lǐng)域更貼近于商務(wù)領(lǐng)域。

轉(zhuǎn)換:

image

轉(zhuǎn)換(Transformation)是ETL解決方案的中的最重要組成部分,它處理抽取,轉(zhuǎn)換,加載各種對(duì)數(shù)據(jù)行的操作。

轉(zhuǎn)換包含一個(gè)或者多個(gè)步驟(step),如讀取文件,過(guò)濾數(shù)據(jù)行,數(shù)據(jù)清洗,或者是將數(shù)據(jù)加載到數(shù)據(jù)庫(kù)。

轉(zhuǎn)換里的步驟通過(guò)跳(hop)來(lái)連接,跳定義了一個(gè)單項(xiàng)通道允許數(shù)據(jù)從一個(gè)步驟到向另一個(gè)步驟流動(dòng)。

在Kettle里,數(shù)據(jù)的單位是行,數(shù)據(jù)流就是數(shù)據(jù)行從一個(gè)步驟到另一個(gè)步驟的移動(dòng)。

數(shù)據(jù)流有時(shí)候被稱為記錄流

Step步驟:

步驟(控件)是轉(zhuǎn)換里的基本組成部分。

image
一個(gè)步驟有如下幾個(gè)關(guān)鍵的步驟特性:
  1. 步驟需要有一個(gè)同一的名字,這個(gè)名字在轉(zhuǎn)換范圍內(nèi)唯一
  2. 每個(gè)步驟都會(huì)讀,寫數(shù)據(jù)行(唯一的例外就是“生成記錄”步驟,該步驟只寫數(shù)據(jù))
  3. 步驟將數(shù)據(jù)寫到一個(gè)或者多個(gè)相關(guān)聯(lián)的輸出跳,再傳送到跳的另一端的步驟
  4. 大多數(shù)的步驟都可以有多個(gè)輸出跳。一個(gè)步驟數(shù)據(jù)發(fā)送可以被設(shè)置為分發(fā)和復(fù)制,分發(fā)是目標(biāo)步驟輪流接收的記錄,復(fù)制是所有記錄被同時(shí)發(fā)送到所有的目標(biāo)步驟。
Hop跳:

跳就是步驟之間帶箭頭的連線,跳定義了步驟之前的數(shù)據(jù)通路

跳實(shí)際上是兩個(gè)步驟之間的被稱為行集的數(shù)據(jù)行緩存(行集的大小可在轉(zhuǎn)換的設(shè)置里定義

當(dāng)行集滿了,向行集寫數(shù)據(jù)的步驟將停止寫入,直到行集又有空間。

當(dāng)數(shù)據(jù)行空了,從行集讀取的步驟停止讀取,直到行集里又有可讀的數(shù)據(jù)行。

數(shù)據(jù)行-數(shù)據(jù)類型:

數(shù)據(jù)以數(shù)據(jù)行的形式沿著步驟移動(dòng),一個(gè)數(shù)據(jù)行時(shí)零到多個(gè)字段的集合,字段包含以下幾種類型。

  • String :字符類型數(shù)據(jù)
  • Number:雙精度浮點(diǎn)數(shù)
  • Integer:帶符號(hào)的長(zhǎng)整型(64位)
  • BigNumber:任意精度數(shù)據(jù)
  • Date:帶毫秒精度的日期時(shí)間值
  • Boolean:取值為true和false的布爾值
  • Binary:二進(jìn)制字段可以包含圖片,聲音,視頻及其他類型的二進(jìn)制數(shù)據(jù)
數(shù)據(jù)行-元數(shù)據(jù):

每個(gè)步驟對(duì)在輸出數(shù)據(jù)行時(shí)都有對(duì)字段的描述,這種描述就是數(shù)據(jù)行的元數(shù)據(jù)。

包含以下一些信息。

  • 名稱:行里的字段名應(yīng)該是唯一的
  • 數(shù)據(jù)類型:字段的數(shù)據(jù)類型
  • 格式:數(shù)據(jù)顯示的方式,如Integer的#,0.00。
  • 長(zhǎng)度:字符串的長(zhǎng)度或者是BigNumber的長(zhǎng)度
  • 精度:BigNumber類型的十進(jìn)制精度
  • 貨幣符號(hào):¥
  • 小數(shù)點(diǎn)符號(hào):十進(jìn)制數(shù)據(jù)的小數(shù)點(diǎn)格式。不同文化背景下小數(shù)點(diǎn)符號(hào)是不同的,一般是(.)或者是(,)。
  • 分組符號(hào):數(shù)值類型數(shù)據(jù)的分組符號(hào),不同文化背景下分組符號(hào)是不同的,一般是點(diǎn)(.),逗號(hào)(,),單引號(hào)(‘)。
并行:

跳的這種基于行集緩存的規(guī)則允許每一個(gè)步驟都是有一個(gè)獨(dú)立的線程運(yùn)行,這樣并發(fā)程度最高。這一規(guī)則也允許數(shù)據(jù)以最小的消耗內(nèi)存的數(shù)據(jù)流的方式處理。在數(shù)據(jù)廠庫(kù)中我們經(jīng)常處理大量數(shù)據(jù),所以這樣并發(fā)低消耗內(nèi)存的方式也是ETL工具的的核心需求。

對(duì)于Kettle的轉(zhuǎn)換,不可能定義一個(gè)執(zhí)行順序,因?yàn)樗胁襟E都以并發(fā)方式執(zhí)行:當(dāng)轉(zhuǎn)換啟動(dòng)后,所有步驟都同時(shí)啟動(dòng)。從它們的輸入跳中讀取數(shù)據(jù),并發(fā)處理過(guò)的數(shù)據(jù)寫到輸入跳中,知道輸入跳中不再有數(shù)據(jù),就中止步驟的運(yùn)行,當(dāng)所有步驟都中止了,整個(gè)轉(zhuǎn)換也就中止了(執(zhí)行順序要與數(shù)據(jù)流向分開(kāi),因?yàn)樗鼈兌际遣⑿械牟僮鳎?/p>

kettle輸入控件

image
(一)XML輸入:(控件-Get Date from Xml)

Xml: xml 是可擴(kuò)展的標(biāo)注語(yǔ)言,xml被設(shè)計(jì)用來(lái)傳輸和存儲(chǔ)數(shù)據(jù).(我們要解析xml的數(shù)據(jù)就使用Xpath

)

Xpath:Xpath是xml路徑語(yǔ)言,它是一種用來(lái)確定xml文檔中的某些部分位置語(yǔ)言。

XPath基于XML樹(shù)狀結(jié)構(gòu),提供在數(shù)據(jù)結(jié)構(gòu)樹(shù)中尋找節(jié)點(diǎn)的能力。

  • 配置參數(shù)
image
  • 輸出
image

(二)JSON輸入

JSON(JavaScript Object Notation )是一種輕量級(jí)的數(shù)據(jù)交換格式

JSON的核心概念:數(shù)組 對(duì)象 屬性

數(shù)組:[]

對(duì)象:{}

屬性:key:value

image

JSONPath:

JSONPath類似于XPath在xml文檔中的定位,JsonPath表達(dá)式通常是用來(lái)路徑檢索或設(shè)置JSON的。

其表達(dá)是可以接受”data-notation”(點(diǎn)記發(fā))和”bracket-notation” (括號(hào)記發(fā))格式

點(diǎn)記發(fā):$.store.book[0].title

括號(hào)記發(fā):$[‘store’][‘book’][0][‘title’]

示例:

image

實(shí)例:

  • 獲取存儲(chǔ)JSON的.js文件,并增加到《選中的文件》
image
  • 名稱可隨便定義,但路徑要相對(duì)匹配
image
  • 輸出JSON數(shù)據(jù)
image

輸出

輸出是轉(zhuǎn)化里面的第二個(gè)分類,屬于ETL中得到L,L也就是加載(屬于數(shù)據(jù)加載的分類)。

(一)表輸出

  • 首先添加Excel數(shù)據(jù),并獲取字段信息

image
  • 創(chuàng)建數(shù)據(jù)庫(kù)連接,獲取表信息。
image
  • 啟動(dòng)
image

轉(zhuǎn)換(重點(diǎn))

Concat fields (控件)就是多個(gè)字段連接起來(lái)形成的新的字段。

值映射(控件)就是把字段的一個(gè)值映射成其他值。

增加常量(控件)就是在本身的數(shù)據(jù)流中添加一列數(shù)據(jù),該列數(shù)據(jù)都是相同的值。

增加序列(控件)就是給數(shù)據(jù)流添加一個(gè)序列字段。

字段選擇(控件)是從數(shù)據(jù)流中選擇字段,改變名稱,修改數(shù)據(jù)類型。

計(jì)算器(控件)是一個(gè)函數(shù)集合來(lái)創(chuàng)建的新的字段,還可以設(shè)置字段是否刪除(臨時(shí)字段)。

剪切字符串(控件)是指定輸入吧v 流字段裁剪的位置剪切出新的字段。

字符串操作(控件)去除字符串兩端的空格和大小寫的切換并生成新的字段。

字符串替換(控件)是指定搜索內(nèi)容和替換內(nèi)容,如果輸入流的字段匹配上搜索內(nèi)容就進(jìn)行替換生成新字段。

去除重復(fù)記錄(控件)去除數(shù)據(jù)流里面相同的數(shù)據(jù)行(執(zhí)行操作前,先進(jìn)性排序)。

排序記錄(控件)是按照指定的字段的升序和降序?qū)?shù)據(jù)流排序。

唯一行(哈希值)(控件)就是刪除數(shù)據(jù)流重復(fù)的行(注意:唯一行(哈希值)和(排序記錄+去除重復(fù)記錄)效果是一樣的,但實(shí)現(xiàn)原理是不一樣的)。

拆分字段(控件)是把字段按照分隔符拆成兩個(gè)或者多個(gè)字段。

列拆分為多行(控件)就是把指定的分隔符的字段進(jìn)行拆分為多行。

列轉(zhuǎn)行(控件)就是如果數(shù)據(jù)一列有相同的值,按照指定的字段,把多行數(shù)據(jù)轉(zhuǎn)換為一行數(shù)據(jù).去除一些原來(lái)的列名,把一列數(shù)據(jù)變成字段。(列轉(zhuǎn)行之前對(duì)數(shù)據(jù)流進(jìn)行排序)

行轉(zhuǎn)列(控件)就是把數(shù)據(jù)字段額字段名轉(zhuǎn)換為一列,把數(shù)據(jù)行變成數(shù)據(jù)列。

行扁平化(控件) 把同一組的多行數(shù)據(jù)合并為一行。 注意:只有數(shù)據(jù)流的同類數(shù)據(jù)數(shù)據(jù)行記錄一致的情況下才可使用。數(shù)據(jù)流必須進(jìn)行排序

Kettle流程控件(重點(diǎn))

流程主要用來(lái)控制數(shù)據(jù)流程和數(shù)據(jù)流向

Switch/Case(控件)讓數(shù)據(jù)流從一路到多路

過(guò)濾記錄(控件)從數(shù)據(jù)流從一路到兩路(很想編程的IF語(yǔ)句true,false)

空操作(控件)作為數(shù)據(jù)流的終點(diǎn)(不執(zhí)行任何擦操作)

中止(控件)是數(shù)據(jù)流的終點(diǎn),如果有數(shù)據(jù)到這里,將會(huì)報(bào)錯(cuò)(用來(lái)檢驗(yàn)數(shù)據(jù)的時(shí)候時(shí)使用)

Kettle 查詢控件(重點(diǎn))

查詢是用來(lái)查詢數(shù)據(jù)源的數(shù)據(jù)并合并到主數(shù)據(jù)中。

Http client(控件)是使用Get的方式提交請(qǐng)求,獲取返回的頁(yè)面內(nèi)容

數(shù)據(jù)庫(kù)查詢(控件)是數(shù)據(jù)庫(kù)中的左連接。

數(shù)據(jù)庫(kù)連接可以執(zhí)行兩個(gè)數(shù)據(jù)庫(kù)的查詢,和單參表的表輸入

Kettle 腳本控件(重點(diǎn))

腳本就是直接通過(guò)程序代碼完成一些復(fù)雜的操作。

javascript腳本

javascript腳本就是使用javascript語(yǔ)言通過(guò)代碼編程完成對(duì)數(shù)據(jù)流的操作。

JS中有很多內(nèi)置函數(shù),可以在編寫JS代碼時(shí)查看

存在兩種不同的模式:不兼容模式和兼容模式

不兼容模式:是默認(rèn)的也是推薦的

兼容模式:兼容老版本的Ketle

獲取字段:
不兼容模式:

MyVar=filedName;(直接一個(gè)變量名)

兼容模式:根據(jù)字段類型不同使用不同方法

MyVar=filedName.getString();(字符串)

MyVar=filedName.getValue();(數(shù)字)

 給字段賦值:

不兼容模式:直接使用字段名

filedName=MyVar;

兼容模式:使用

        filedName.setValue(MyVar);

Java腳本

Java腳本就是使用java語(yǔ)言通過(guò)代碼編程來(lái)完成對(duì)數(shù)據(jù)流的操作。

內(nèi)置很多函數(shù)可以使用。

Main:

main函數(shù)對(duì)應(yīng)一個(gè)ProcessRow()函數(shù),ProcessRow()函數(shù)是用來(lái)處理數(shù)據(jù)流的場(chǎng)所。

SQL******腳本(控件)可以執(zhí)行一個(gè)update語(yǔ)句用來(lái)更新某個(gè)表的信息

作業(yè)

簡(jiǎn)介:大多數(shù)ETL項(xiàng)目都需要完成各種各樣的維護(hù)工作。

例如,如何傳送文件;驗(yàn)證數(shù)據(jù)庫(kù)表的存在,等等。而這些操作都是按照一定順序完成的。因?yàn)檗D(zhuǎn)換以并行方式執(zhí)行,就需要一個(gè)可以串行執(zhí)行的作業(yè)來(lái)處理這些操作。

一個(gè)作業(yè)包含一個(gè)或者多個(gè)作業(yè)項(xiàng),這些作業(yè)項(xiàng)以某種順序來(lái)執(zhí)行。作業(yè)執(zhí)行順序由作業(yè)項(xiàng)之間的跳(JOB HOP)和每個(gè)作業(yè)執(zhí)行結(jié)果來(lái)決定。

作業(yè)項(xiàng)

作業(yè)項(xiàng)是作業(yè)的基本構(gòu)成部分,如同轉(zhuǎn)換的步驟,作業(yè)項(xiàng)也可以通過(guò)圖標(biāo)的方式圖形化展示。

但是,如果你仔細(xì)觀察,還是會(huì)發(fā)現(xiàn)作業(yè)項(xiàng)有一些地方不同于步驟;

在作業(yè)項(xiàng)之間可以傳遞一個(gè)結(jié)果對(duì)象。這個(gè)結(jié)果對(duì)象里面包含了數(shù)據(jù)行,他們不是以數(shù)據(jù)流的方式來(lái)傳遞到,二十等待一個(gè)作業(yè)執(zhí)行完畢后再傳遞給下一個(gè)作業(yè)。

作業(yè)跳

作業(yè)的跳是作業(yè)項(xiàng)之間的連接線。他定義了作業(yè)的執(zhí)行路徑。作業(yè)里每個(gè)作業(yè)項(xiàng)的不同運(yùn)行結(jié)果決定了作業(yè)的不同執(zhí)行路徑。

① 無(wú)條件執(zhí)行:不論上個(gè)作業(yè)項(xiàng)執(zhí)行成功或者失敗,下一個(gè)作業(yè)項(xiàng)都會(huì)執(zhí)行。這是一種藍(lán)色的連接線,上面有一個(gè)鎖的標(biāo)。

② 當(dāng)運(yùn)行結(jié)果為真時(shí)執(zhí)行:當(dāng)上一個(gè)作業(yè)項(xiàng)執(zhí)行結(jié)果為真時(shí),執(zhí)行下一個(gè)作業(yè)項(xiàng)。通常在需要無(wú)錯(cuò)誤執(zhí)行的情況下使用。這是一條綠色的連接線,上面有對(duì)勾號(hào)的圖標(biāo)。

③ 當(dāng)運(yùn)行結(jié)果為假時(shí)執(zhí)行:當(dāng)上一個(gè)作業(yè)項(xiàng)執(zhí)行結(jié)果為假或者沒(méi)有執(zhí)行成功,執(zhí)行一按一個(gè)作業(yè)項(xiàng),這是一條紅色的連接線,上面有紅色停止的圖標(biāo)。

參數(shù):

對(duì)于ETL參數(shù)傳遞是一個(gè)非常重要的環(huán)節(jié),因?yàn)閰⒊龅膫鬟f會(huì)涉及到業(yè)務(wù)參數(shù)是如何抽取的。

參數(shù)分為兩種:全局參數(shù)和局部參數(shù)

全局參數(shù):定義在當(dāng)前用戶下.kettle文件夾下的kettle.properties文件來(lái)定義。

定義方式是采用鍵=值的方式來(lái)定義 如:start_date=120;

注意:配置前變量后需要重啟Kettle

局部參數(shù):是通過(guò)”Set Variables” 于”Get Variables” 方式來(lái)設(shè)置

注意:在”Set Variables”時(shí)在當(dāng)前轉(zhuǎn)換不能馬上使用,需要在作業(yè)的下一個(gè)步驟執(zhí)行。

參數(shù)的使用:Kettle參數(shù)的使用:(1)%%變量名%%(2)${變量名}

注意:在SQL中使用變量時(shí)需要吧“是否替換參數(shù)”勾選上,否則變量無(wú)法生效。

常量傳遞:

常量傳遞就是先自定義常量數(shù)據(jù),在表輸入的SQl語(yǔ)句里面使用?來(lái)代替。

?替換的順序就是常量調(diào)用的順序。

轉(zhuǎn)換命名參數(shù):

轉(zhuǎn)換命名參數(shù)就是在轉(zhuǎn)換內(nèi)部定義的變量,作用范圍是轉(zhuǎn)換內(nèi)部。

在轉(zhuǎn)換的空白處右鍵,選擇轉(zhuǎn)換設(shè)置就可以看見(jiàn)。

設(shè)置變量,獲取變量:

在轉(zhuǎn)換里面有一個(gè)作業(yè)分類,里面是轉(zhuǎn)換變量和設(shè)置變量的分類。

注意:“獲取變量”時(shí)在當(dāng)前轉(zhuǎn)換當(dāng)時(shí)是不能馬上使用的,需要在作業(yè)的下一個(gè)步驟使用

---------變量也可以作業(yè)里面設(shè)置(作業(yè)下有一個(gè)通用的模塊下的《設(shè)置變量》)

結(jié)束。。。。謝謝

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容