Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 a4yy欧美一区二区三区,伊人电影综合网,香蕉免费看一区二区三区

          整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          數(shù)據(jù)科學(xué)家易犯的十大編碼錯(cuò)誤,你中招了嗎?

          數(shù)據(jù)科學(xué)家易犯的十大編碼錯(cuò)誤,你中招了嗎?

          據(jù)科學(xué)家比軟件工程師擅長(zhǎng)統(tǒng)計(jì),又比統(tǒng)計(jì)學(xué)家擅長(zhǎng)軟件工程。聽起來牛逼轟轟,事實(shí)卻是,許多數(shù)據(jù)科學(xué)家有統(tǒng)計(jì)學(xué)背景,卻沒有什么軟件工程方面的經(jīng)驗(yàn),因此在編碼時(shí)容易犯一些簡(jiǎn)單的錯(cuò)誤。作為一名高級(jí)數(shù)據(jù)科學(xué)家,本文作者總結(jié)了他在工作中常見數(shù)據(jù)科學(xué)家犯的十大錯(cuò)誤。

          我是一名高級(jí)數(shù)據(jù)科學(xué)家,在 Stackoverflow 的 python 編碼中排前 1%,而且還與眾多(初級(jí))數(shù)據(jù)科學(xué)家一起工作。下文列出了我常見到的 10 個(gè)錯(cuò)誤。

          沒有共享代碼中引用的數(shù)據(jù)

          數(shù)據(jù)科學(xué)需要代碼和數(shù)據(jù)。所以為了讓其他人能夠復(fù)現(xiàn)自己做出來的結(jié)果,你需要提供代碼中涉及的數(shù)據(jù)。這看起來很簡(jiǎn)單,但許多人會(huì)忘記共享代碼中需要的數(shù)據(jù)。

          import pandas as pd
          df1=pd.read_csv('file-i-dont-have.csv') # fails
          do_stuff(df)
          

          解決方案:用 d6tpipe 共享代碼中的數(shù)據(jù)文件,或者將數(shù)據(jù)文件上傳到 S3/網(wǎng)頁/Google 云等,還可以將數(shù)據(jù)文件保存到數(shù)據(jù)庫中,以便收件人檢索文件(但不要將數(shù)據(jù)添加到 git 中,這一點(diǎn)后面的內(nèi)容會(huì)講到)。

          硬編碼其他人無法訪問的路徑

          和錯(cuò)誤 1 類似,如果硬編碼其他人無法訪問的路徑,他們就沒法運(yùn)行你的代碼,而且在很多地方都必須要手動(dòng)修改路徑。Booo!

          import pandas as pd
          df=pd.read_csv('/path/i-dont/have/data.csv') # fails
          do_stuff(df)
          # or 
          impor os
          os.chdir('c:\\Users\\yourname\\desktop\\python') # fails
          

          解決方案:使用相對(duì)路徑、全局路徑配置變量或 d6tpipe,這樣其他人就可以輕易訪問你的數(shù)據(jù)了。

          將數(shù)據(jù)和代碼混在一起

          既然數(shù)據(jù)科學(xué)代碼需要數(shù)據(jù),為什么不將代碼和數(shù)據(jù)存儲(chǔ)在同一個(gè)目錄中呢?但你運(yùn)行代碼時(shí),這個(gè)目錄中還會(huì)存儲(chǔ)圖像、報(bào)告以及其他垃圾文件。亂成一團(tuán)!

          ├── data.csv
          ├── ingest.py
          ├── other-data.csv
          ├── output.png
          ├── report.html
          └── run.py
          

          解決方案:對(duì)目錄進(jìn)行分類,比如數(shù)據(jù)、報(bào)告、代碼等。參閱 Cookiecutter Data Science 或 d6tflow 項(xiàng)目模板,并用問題 1 中提到的工具存儲(chǔ)以及共享數(shù)據(jù)。

          • Cookiecutter Data Science:https://drivendata.github.io/cookiecutter-data-science/#directory-structure
          • d6tflow 項(xiàng)目模板:https://github.com/d6t/d6tflow-template

          用 Git 提交數(shù)據(jù)

          大多數(shù)人現(xiàn)在都會(huì)版本控制他們的代碼(如果你沒有這么做那就是另一個(gè)問題了!)。在共享數(shù)據(jù)時(shí),可能很容易將數(shù)據(jù)文件添加到版本控制中。對(duì)一些小文件來說這沒什么問題。但 git 無法優(yōu)化數(shù)據(jù),尤其是對(duì)大型文件而言。

          git add data.csv
          

          解決方案:使用問題 1 中提到的工具來存儲(chǔ)和共享數(shù)據(jù)。如果你真的需要對(duì)數(shù)據(jù)進(jìn)行版本控制,請(qǐng)參閱 d6tpipe、DVC 和 Git Large File Storage。

          • DVC:https://dvc.org/
          • Git Large File Storage:https://git-lfs.github.com/

          寫函數(shù)而不是 DAG

          數(shù)據(jù)已經(jīng)討論得夠多了,接下來我們談?wù)剬?shí)際的代碼。你在學(xué)編程時(shí),首先學(xué)的就是函數(shù),數(shù)據(jù)科學(xué)代碼主要由一系列線性運(yùn)行的函數(shù)組成。這會(huì)引發(fā)一些問題,詳情請(qǐng)參閱「4 Reasons Why Your Machine Learning Code is Probably Bad。」

          • 地址:https://towardsdatascience.com/4-reasons-why-your-machine-learning-code-is-probably-bad-c291752e4953
          def process_data(data, parameter):
           data=do_stuff(data)
           data.to_pickle('data.pkl')
          data=pd.read_csv('data.csv')
          process_data(data)
          df_train=pd.read_pickle(df_train)
          model=sklearn.svm.SVC()
          model.fit(df_train.iloc[:,:-1], df_train['y'])
          

          解決方案:與其用線性鏈接函數(shù),不如寫一組有依賴關(guān)系的任務(wù)。可以用 d6tflow 或者 airflow。

          寫 for 循環(huán)

          和函數(shù)一樣,for 循環(huán)也是你在學(xué)代碼時(shí)最先學(xué)的。這種語句易于理解,但運(yùn)行很慢且過于冗長(zhǎng),這種情況通常表示你不知道用什么替代向量化。

          x=range(10)
          avg=sum(x)/len(x); std=math.sqrt(sum((i-avg)**2 for i in x)/len(x));
          zscore=[(i-avg)/std for x]
          # should be: scipy.stats.zscore(x)
          # or
          groupavg=[]
          for i in df['g'].unique():
           dfg=df[df[g']==i]
           groupavg.append(dfg['g'].mean())
          # should be: df.groupby('g').mean()
          

          解決方案:NumPy、SciPy 和 pandas 都有向量化函數(shù),它們可以處理大部分你覺得需要用 for 循環(huán)解決的問題。

          沒有寫單元測(cè)試

          隨著數(shù)據(jù)、參數(shù)或者用戶輸入的改變,你的代碼可能會(huì)中斷,而你有時(shí)候可能沒注意到這一點(diǎn)。這就會(huì)導(dǎo)致錯(cuò)誤的輸出,如果有人根據(jù)你的輸出做決策的話,那么錯(cuò)誤的數(shù)據(jù)就會(huì)導(dǎo)致錯(cuò)誤的決策!

          解決方案:用 assert 語句檢查數(shù)據(jù)質(zhì)量。Pandas 也有相同的測(cè)試,d6tstack 可以檢查數(shù)據(jù)的獲取,d6tjoin 可以檢查數(shù)據(jù)的連接。檢查數(shù)據(jù)的示例代碼如下:

          • d6tstack:https://github.com/d6t/d6tstack
          • d6tjoin:https://github.com/d6t/d6tjoin/blob/master/examples-prejoin.ipynb
          assert df['id'].unique().shape[0]==len(ids) # have data for all ids?
          assert df.isna().sum()<0.9 # catch missing values
          assert df.groupby(['g','date']).size().max()==1 # no duplicate values/date?
          assert d6tjoin.utils.PreJoin([df1,df2],['id','date']).is_all_matched() # all ids matched?
          

          沒有注釋代碼

          我明白你急著做分析。于是你把代碼拼湊起來得到結(jié)果,把結(jié)果交給你的客戶或者老板。一周之后他們找到你,問你「你能改掉 xyz 嗎?」或「你能更新一下結(jié)果嗎?」。然后你和自己的代碼大眼瞪小眼,既不記得你為什么要這么做,也不記得你做過什么。現(xiàn)在想象一下其他人運(yùn)行這段代碼時(shí)的心情。

          def some_complicated_function(data):
           data=data[data['column']!='wrong']
           data=data.groupby('date').apply(lambda x: complicated_stuff(x))
           data=data[data['value']<0.9]
           return data
          

          解決方案:即便你已經(jīng)完成了分析,也要花時(shí)間注釋一下你做過什么。你會(huì)感謝自己的,當(dāng)然其他人會(huì)更加感謝你!這樣你看起來會(huì)更專業(yè)!

          把數(shù)據(jù)存成 csv 或 pickle

          說回?cái)?shù)據(jù),畢竟我們討論的是數(shù)據(jù)科學(xué)。就像函數(shù)和 for 循環(huán)一樣,CSV 和 pickle 文件也很常用,但它們其實(shí)并沒有那么好。CSV 不包含模式(schema),所以每個(gè)人都必須重新解析數(shù)字和日期。Pickle 可以解決這一點(diǎn),但只能用在 Python 中,而且不能壓縮。這兩種格式都不適合存儲(chǔ)大型數(shù)據(jù)集。

          def process_data(data, parameter):
           data=do_stuff(data)
           data.to_pickle('data.pkl')
          data=pd.read_csv('data.csv')
          process_data(data)
          df_train=pd.read_pickle(df_train)
          

          解決方案:用 parquet 或者其他帶有數(shù)據(jù)模式的二進(jìn)制數(shù)據(jù)格式,最好還能壓縮數(shù)據(jù)。d6tflow 可以自動(dòng)將數(shù)據(jù)輸出存儲(chǔ)為 parquet,這樣你就不用解決這個(gè)問題了。

          • parquet:https://github.com/dask/fastparquet

          使用 Jupyter notebook

          這個(gè)結(jié)論還有一些爭(zhēng)議——Jupyter notebook 就像 CSV 一樣常用。很多人都會(huì)用到它們。但這并不能讓它們變得更好。Jupyter notebook 助長(zhǎng)了上面提到的許多不好的軟件工程習(xí)慣,特別是:

          1. 你會(huì)把所有文件存在一個(gè)目錄中;
          2. 你寫的代碼是自上而下運(yùn)行的,而不是 DAG;
          3. 你不會(huì)模塊化你的代碼;
          4. 代碼難以調(diào)試;
          5. 代碼和輸出會(huì)混合在一個(gè)文件中;
          6. 不能很好地進(jìn)行版本控制。

          Jupyter notebook 很容易上手,但規(guī)模太小。

          解決方案:用 pycharm 和/或 spyder。

          原文鏈接:https://medium.com/m/global-identity?redirectUrl=https%3A%2F%2Ftowardsdatascience.com%2Ftop-10-coding-mistakes-made-by-data-scientists-bb5bc82faaee

          要:本次分享主要介紹 Hive數(shù)據(jù)如何遷移到MaxCompute。MMA(MaxCompute Migration Assist)是一款MaxCompute數(shù)據(jù)遷移工具,本文將為大家介紹MMA工具的功能、技術(shù)架構(gòu)和實(shí)現(xiàn)原理,再通過實(shí)際操作MMA,演示將Hive數(shù)據(jù)遷移到MaxCompute。

          演講嘉賓簡(jiǎn)介:阿里云智能產(chǎn)品專家-云花

          精彩視頻回顧:Hive數(shù)據(jù)如何同步到MaxCompute

          以下內(nèi)容根據(jù)演講視頻以及PPT整理而成。本次分享主要圍繞以下兩個(gè)方面:一、MMA功能介紹、技術(shù)架構(gòu)和原理二、MMA數(shù)據(jù)遷移操作演示

          一、MMA功能介紹、技術(shù)架構(gòu)和原理1.MMA功能介紹MMA主要覆蓋的場(chǎng)景包括批處理,存儲(chǔ),數(shù)據(jù)集成,作業(yè)編排及調(diào)度。MMA提供遷移評(píng)估分析功能,自動(dòng)化生成遷移評(píng)估報(bào)告。遷移評(píng)估報(bào)告會(huì)報(bào)告出從Hive表的數(shù)據(jù)結(jié)構(gòu)到MaxCompute的數(shù)據(jù)結(jié)構(gòu)之間是否有數(shù)據(jù)類型映射兼容性問題,如語法問題。MMA支持自動(dòng)化數(shù)據(jù)遷移功能,支持批量建表以及數(shù)據(jù)自動(dòng)化批量遷移。另外,MMA還支持作業(yè)語法分析,可以檢查Hive SQL能否直接運(yùn)行在MaxCompute里。MMA還支持工作流遷移,對(duì)主流數(shù)據(jù)集成工具Sqoop進(jìn)行作業(yè)的遷移轉(zhuǎn)換,并自動(dòng)創(chuàng)新DataWorks數(shù)據(jù)繼承作業(yè)。

          2.MMA遷移服務(wù)架構(gòu)MMA遷移服務(wù)架構(gòu)如下圖。左側(cè)是客戶Hadoop集群,右側(cè)的是Aliyun 大數(shù)據(jù)服務(wù),主要是DataWorks和MaxCompute。MMA工具會(huì)跑在客戶的Hadoop集群上,客戶的服務(wù)器需要能夠訪問Hive Server。在機(jī)器上部署MMA客戶端工具時(shí)會(huì)自動(dòng)化獲取Hive Meta里的數(shù)據(jù),既將Hive的Meta數(shù)據(jù)從MySQL中讀出來,還可以將Meta信息自動(dòng)轉(zhuǎn)換成MaxCompute DDL,然后用DDL在MaxCompute中批量創(chuàng)建表,批量拉起數(shù)據(jù)同步的作業(yè),向Hive Server并發(fā)提交Hive SQL作業(yè)。基于Hive SQL作業(yè)調(diào)用一個(gè)UDF,UDF里面會(huì)集成Tunnel的SDK,基于Tunnel將數(shù)據(jù)批量寫到MaxCompute的表中。作業(yè)和工作流的遷移也是基于MMA客戶端工具自動(dòng)發(fā)現(xiàn)的Hive Meta數(shù)據(jù),做工作流的作業(yè)檢查,包括把工作流的組件中的工作流的配置批量轉(zhuǎn)換成DataWorks工作流的配置,直接生成DataWorks工作流。以上步驟完成了數(shù)據(jù)到作業(yè)到工作流的遷移。最后一步是遷移完成后需要基于MaxCompute和DataWorks架構(gòu)對(duì)接業(yè)務(wù)系統(tǒng)。

          3.MMA Agent技術(shù)構(gòu)架和原理通過客戶端和服務(wù)端,MMA可支持?jǐn)?shù)據(jù)和工作流的批量遷移。安裝在客戶服務(wù)器上的MMA客戶端工具包含下圖中的四個(gè)能力。首先可自動(dòng)獲取Hive Metadata,并自動(dòng)創(chuàng)建生成DDL和UDTF,而且可批量創(chuàng)建表和批量Hive數(shù)據(jù)遷移。相應(yīng)的,MMA有四個(gè)主要組件。Meta Carrier工具自動(dòng)將Hive Meta信息提取出來,在本地生成Hive Meta結(jié)構(gòu)。Meta Processor是基于Meta Carrier工具產(chǎn)出的結(jié)果,基于Hive Meta數(shù)據(jù)批量轉(zhuǎn)成MaxCompute的DDL,既批量轉(zhuǎn)成建表語句和數(shù)據(jù)類型的轉(zhuǎn)換。此外,MMA客戶端工具還內(nèi)置了ODPS Console,基于ODPS Console將Meta Processor產(chǎn)出的ODPS DDL在MaxCompute上批量創(chuàng)建表。最后基于Data Carrier批量創(chuàng)建Hive SQL作業(yè)。每個(gè)Hive SQL作業(yè)相當(dāng)于多個(gè)表或者多個(gè)分區(qū)并行的數(shù)據(jù)的同步。

          二、MMA數(shù)據(jù)遷移操作演示1.環(huán)境準(zhǔn)備如下圖所示,MMA環(huán)境運(yùn)行要求是jdk1.6版本以上,Python3+。另外,運(yùn)行MMA的機(jī)器,通過Hive Client提交Hive SQL的作業(yè)。機(jī)器還需要可以訪問Hive Server,并連接MaxCompute服務(wù)。下圖右側(cè)的場(chǎng)景案例是客戶在基于MMA做同步數(shù)據(jù)時(shí)發(fā)現(xiàn)的問題。例子中客戶有自己的IDC,在阿里云有自己的ECS,客戶從IDC拉一條專線訪問阿里云。在安裝MMA之前,客戶可以從ECS上直接訪問MaxCompute,但I(xiàn)DC里的機(jī)器不能訪問MaxCompute。此時(shí)需要在這條專線上增加VBR路由配置,既在邊界路由上增加一個(gè)配置。配置之后可以打通從IDC到ECS,甚至到MaxCompute服務(wù)的網(wǎng)絡(luò)訪問。

          2.下載和編譯工具包下載編譯工具包有兩種方法。一是下載下圖中編譯好的工具包。此外,由于用戶的Hive版本各不相同,用戶可以根據(jù)MMA官網(wǎng)上提供的GitHub地址下載源碼,拉到本地進(jìn)行編譯。

          3.MMA Agent操作說明使用meta-carrier采集Hive Metadata:機(jī)器提前安裝好Hadoop環(huán)境,本地有Hive Server。提前下載客戶端的odps-data-carrier.zip包,并在本地解壓。解壓完成后會(huì)顯示下圖所示目錄。bin目錄下有幾個(gè)文件,首先是MMA的幾個(gè)核心角色:meta-carrier、meta-processor、odps_ddl_runner用于批量創(chuàng)建表,hive_udtf_sql_runner用于同步數(shù)據(jù)。libs目錄下是工具依賴的jar包和庫。 res目錄的console目錄下的bin目錄包含odpscmd,是MMA客戶端的工具,odps_config,ini配置文件。本地Hive上面有三個(gè)庫,其中dma_demo庫下有五個(gè)表,可將五個(gè)表自動(dòng)批量同步到MaxCompute上。首先需要在MaxCompute上創(chuàng)建一個(gè)project,既在DataWorks控制臺(tái)創(chuàng)建一個(gè)空Project。打開新的命令窗口,在本地運(yùn)行的ODPS Command客戶端工具,連接新創(chuàng)建的空的project。在已經(jīng)安裝了MMA Hive的機(jī)器上運(yùn)行,解壓,進(jìn)入odps-data-carrier工具的目錄。執(zhí)行 bin/meta-carrier -h查看其參數(shù)說明,-d表示用戶可以指定數(shù)據(jù)庫,通過指定數(shù)據(jù)庫提取meta數(shù)據(jù),若不指定,會(huì)將Hive下所有的庫的meta都拉取出來。-o指定輸出目錄,-t參數(shù)指定表,-u參數(shù)指定uri地址,即Hive Meta的地址。開始測(cè)試時(shí)首先指定地址,因?yàn)槭莟hirft地址,所以用thirft協(xié)議連接。此外由于Hive Meta在本地,所以只需要將dma_demo庫的meta拉取出來,加-o參數(shù),指定目錄。通過tree meta可以查看meta目錄結(jié)構(gòu)。meta目錄下生成和數(shù)據(jù)庫同名的dma_demo目錄。dma_demo目錄下的json文件是描述數(shù)據(jù)庫meta信息的文件。partition_meta里面的兩個(gè)表是分區(qū)表,table_meta的表是非分區(qū)表,會(huì)把所有表集的meta信息寫在下面。

          使用network-measurement-tool:網(wǎng)絡(luò)測(cè)量工具network-measurement-tool用于網(wǎng)絡(luò)測(cè)速,測(cè)量Hive集群到MaxCompute各region的網(wǎng)絡(luò)連通質(zhì)量。通過網(wǎng)絡(luò)測(cè)速可以知道網(wǎng)絡(luò)傳輸速度和大概的數(shù)據(jù)量,根據(jù)網(wǎng)絡(luò)傳輸速度預(yù)估數(shù)據(jù)傳輸時(shí)間。network-measurement-tool工具連接MaxCompute上所有region的節(jié)點(diǎn)ENDPOINT地址,由最快到最慢做測(cè)速排序。下圖中執(zhí)行結(jié)果最快的是HANGZHOU,連接時(shí)間為51ms,最慢的是一個(gè)海外region KUALA_LUMPUR,連接時(shí)間為3393ms。

          使用sql-checker檢查Hive SQL是否可以直接在MaxCompute上執(zhí)行:sql-checker可用于檢查Hive SQL語法兼容性,判斷SQL能否直接在MaxCompute上運(yùn)行。其參數(shù)input要指定meta目錄,指定缺省project和sql參數(shù)。若執(zhí)行結(jié)果返回其兼容性O(shè)K,即此sql語句可以直接在MaxCompute上運(yùn)行。

          使用meta-processor生成ODPS DDL和Hive UDTF SQL:通過第一步已經(jīng)拉出了Hive Meta庫的metadata信息。下一步需要將Hive Meta轉(zhuǎn)換成MaxCompute DDL。使用bin/meta-processor -h查看參數(shù)。-i即input,-o是output目錄。bin/meta-processor的-i就是第一個(gè)命令的輸出結(jié)果,代表meta的目錄,存放的是carrier拉出的Hive Meta數(shù)據(jù)。指定-i meta -o output。將bin/meta-processor運(yùn)行結(jié)果放入output中。生成output目錄。tree output可查看結(jié)構(gòu)。output目錄下也會(huì)生成一個(gè)以MaxCompute的project命名的dma_demo目錄。dma_demo目錄下面有一個(gè)hive_udtf_sql目錄,目錄下面的.sql用于批量數(shù)據(jù)遷移。還包含odps_ddl目錄,用于后續(xù)批量創(chuàng)建表,目錄下的.sql是創(chuàng)建表的語句。

          使用odps_ddl_runner.py批量創(chuàng)建表和分區(qū):既然DDL已經(jīng)生成,下一步需要批量創(chuàng)建表。批量創(chuàng)建表依賴MaxCompute的命令行工具(客戶端工具)。工具包一級(jí)目錄下的odps_config包含幾個(gè)基本參數(shù),其中project_name、access_id、access_key、end_point為必填項(xiàng)。配置完成可以開始批量創(chuàng)建表。批量創(chuàng)建表工具要執(zhí)行Python命令,python36 bin/odps_ddl_runner.py -h。參數(shù)中input參數(shù)由meta processer自動(dòng)生成,odpscmd參數(shù)不是必須指定的,它會(huì)默認(rèn)找到所在目錄,不需要單獨(dú)配置參數(shù)。創(chuàng)建表過程要拉起odps_command工具,基于客戶端工具來向MaxCompute提交建表語句。通過show table查看是否創(chuàng)建了五個(gè)表,再查看分區(qū)是否也建好。若Hive和MaxCompute上的分區(qū)創(chuàng)建完成,兩邊的表結(jié)構(gòu)也應(yīng)相同。

          使用hive_udtf_sql_runner.py遷移數(shù)據(jù):通過命令行python36 bin/hive_udtf_sql_runner.py開始讀output目錄下的.sql語句。查看python36 bin/hive_udtf_sql_runner.py命令的參數(shù),Input_all會(huì)批量遷移output下所有數(shù)據(jù)。若只想做單表的遷移或者單分區(qū)的遷移,需要使用input_single_file參數(shù)。parallelism參數(shù)表示并行度。數(shù)據(jù)遷移完成后在MaxCompute中查看表中是否有數(shù)據(jù)。對(duì)比MaxCompute中的數(shù)據(jù)和Hive中對(duì)應(yīng)表的數(shù)據(jù)。若其size相同,Hive和MaxCompute中對(duì)應(yīng)表的數(shù)據(jù)相同,說明已經(jīng)完整遷移數(shù)據(jù)。

          進(jìn)階功能1:僅生成指定的database或table的metadata:在生成meta時(shí)可以不生成整個(gè)數(shù)據(jù)庫的meta,可以指定一個(gè)表,生成一個(gè)表的meta。Meta carrier 工具提供了抓取指定數(shù)據(jù)庫可表的能力。

          進(jìn)階功能2:進(jìn)靈活的hive到MaxCompute映射:如果用戶需要自定義MaxCompute上的表,可以更改命名,加前綴或后綴,修改自定義字段名。如可以修改MaxCompute DDL里的json文件實(shí)現(xiàn)表名或字段名的自定義。

          進(jìn)階功能3:?jiǎn)伪砘騿畏謪^(qū)遷移:上面的例子中已經(jīng)批量遷移五張表,通過drop table inventory,演示單分區(qū)遷移。首先若只需同步一個(gè)分區(qū)的數(shù)據(jù),需要重新創(chuàng)建一張表。執(zhí)行python36 bin/odps_ddl_runner.py創(chuàng)建表,指定其output目錄,開始批量創(chuàng)建表。此時(shí)inventory表以及其五個(gè)分區(qū)已經(jīng)創(chuàng)建完成。但創(chuàng)建的分區(qū)中沒有數(shù)據(jù),可指定其中一個(gè)分區(qū),如第二個(gè)分區(qū)。通過使用input_single_file參數(shù),指定具體分區(qū)的sql目錄。可指定目錄為output/dma_demo/hive_udtf_sql/single_partition/inventory_1.sql。執(zhí)行完成后查看結(jié)果,對(duì)比在Hive上第二分區(qū)的數(shù)據(jù)和遷移進(jìn)MaxCompute的單分區(qū)的數(shù)據(jù),若兩個(gè)單分區(qū)數(shù)據(jù)一致,則表示遷移完成。

          4.使用DataWorks自動(dòng)遷移數(shù)據(jù)和工作流MMA1.0版本還未將工作流遷移做成服務(wù)化功能,目前還是一個(gè)線下工具。客戶需要根據(jù)下圖模板生成相應(yīng)目錄。在做工作流遷移時(shí),如果使用開源組件,可以按照模板將配置放到相應(yīng)目錄下。如果不使用開源組件,如自研的工作流調(diào)度編排服務(wù),可基于標(biāo)準(zhǔn)化模板,按照模板的目錄結(jié)構(gòu)生成用戶自己的工作流數(shù)據(jù),打成zip包上傳到DataWorks。目前MMA1.0還需要客戶手動(dòng)打包文件上傳zip包,后臺(tái)會(huì)進(jìn)行自動(dòng)解析并加載到DataWorks工作流。上傳完成后,DataWorks服務(wù)會(huì)根據(jù)ODPS DDL 批量生成MaxCompute的table。MaxCompute表創(chuàng)建后,DataWorks服務(wù)會(huì)自動(dòng)拉起DataX的數(shù)據(jù)同步任務(wù),完成批量數(shù)據(jù)遷移。

          下圖是可配置的項(xiàng)目描述文件project.xml,其中project信息可以自定義。另外一個(gè)是工作流描述文件,workflow.xml中是工作流自定義的參數(shù),用戶可以通過編輯配置文件進(jìn)行修改。

          5.其他類型作業(yè)的遷移方案UDF、MR遷移:用戶直接將jar包上傳到MaxCompute上,開啟2.0支持,開啟對(duì)Hive兼容的flag。將Hive兼容的flag設(shè)置為true,再在MaxCompute下直接遷移Hive下的UDF和MR。需求注意不支持UDF,MR中直接訪問文件系統(tǒng),網(wǎng)絡(luò)訪問和外部數(shù)據(jù)源連接。外表遷移:原則上能結(jié)構(gòu)化的數(shù)據(jù)盡量遷移到MaxCompute內(nèi)部表。如果必須通過外表訪問外部文件,建議先將數(shù)據(jù)從HDPS遷移到OSS或OTS,再在MaxCompute中創(chuàng)建外部表,實(shí)現(xiàn)對(duì)文件的訪問。Spark作業(yè)遷移:MMA對(duì)開源Spark的語法完全兼容。用戶只需要下載Spark On MaxCompute客戶端,在編寫Spark SQL時(shí)僅增加MaxCompute的連接參數(shù),其它部分和Spark SQL的語法相同。

          6.查看遷移評(píng)估報(bào)告創(chuàng)建MaxCompute DDL完成后,除了生成DDL會(huì)SQL以外,還會(huì)生成遷移評(píng)估報(bào)告report.html文件。遷移評(píng)估報(bào)告是一個(gè)兼容性報(bào)告,顯示Hive表的數(shù)據(jù)結(jié)構(gòu)和MaxCompute表的數(shù)據(jù)結(jié)構(gòu)之間的映射關(guān)系是否有風(fēng)險(xiǎn),并標(biāo)識(shí)風(fēng)險(xiǎn)等級(jí)。另外會(huì)給出明細(xì)說明以及預(yù)警提示,如數(shù)據(jù)類型不兼容或語法不兼容等。用戶在遷移之前可以查看此報(bào)告評(píng)估遷移風(fēng)險(xiǎn)。


          查看更多:https://yqh.aliyun.com/detail/6648?utm_content=g_1000106727

          上云就看云棲號(hào):更多云資訊,上云案例,最佳實(shí)踐,產(chǎn)品入門,訪問:https://yqh.aliyun.com/

          口測(cè)試【接口:系統(tǒng)與系統(tǒng)之間,組件與組件之間,數(shù)據(jù)傳遞交互的通道】

          一、簡(jiǎn)介

          1.1接口概念:指的是系統(tǒng)或組件之間的交互點(diǎn),通過這些交互點(diǎn)可以實(shí)現(xiàn)數(shù)據(jù)的交互;可分為硬件接口和軟件接口;

          服務(wù)器開了個(gè)口,客戶端發(fā)送請(qǐng)求

          1.2接口的類型:

          ①按協(xié)議劃分:http、tcp、ip②按語言劃分:C++、java、php

          ③按范圍劃分,系統(tǒng)之間的接口和程序內(nèi)部的接口

          系統(tǒng)之間的接口:多個(gè)內(nèi)部系統(tǒng)之間的交互【用戶系統(tǒng)、訂單系統(tǒng)、商品系統(tǒng)】,內(nèi)部系統(tǒng)與外部系統(tǒng)【支付系統(tǒng)】之間的交互

          程序內(nèi)部的接口:方法與方法之間,函數(shù)與函數(shù)之間【傳入不同的數(shù)據(jù),輸出不同的值,叫接口函數(shù)】,模塊與模塊之間的交互

          1.3接口測(cè)試的概念

          接口測(cè)試:對(duì)系統(tǒng)或組件之間的接口進(jìn)行測(cè)試,校驗(yàn)傳遞的數(shù)據(jù)正確性和邏輯依賴關(guān)系(淘寶先登錄才能看訂單,即使復(fù)制了訂單的網(wǎng)頁,但是未登錄,復(fù)制的訂單網(wǎng)頁打開還是跳轉(zhuǎn)登錄界面。)的正確性。【校驗(yàn)數(shù)據(jù)的交換、傳遞和控制管理的過程,以及相互邏輯依賴關(guān)系。】

          1.4接口測(cè)試原理【接口測(cè)試主要測(cè)試目標(biāo):服務(wù)器,功能測(cè)試:測(cè)試客戶端】

          1>怎么測(cè)?模擬客戶端,向服務(wù)器發(fā)送請(qǐng)求

          2>用什么測(cè)?工具:fiddler、postman、jmeter;代碼:python+UnitTest框架+Requests框架

          3>測(cè)試什么?測(cè)試服務(wù)器針對(duì)客戶端請(qǐng)求,回應(yīng)的響應(yīng)數(shù)據(jù)是否與預(yù)期結(jié)果一致

          1.5特點(diǎn)

          ①測(cè)試可以提前介入,提早發(fā)現(xiàn)bug,符合質(zhì)量控制前移的理念

          ②可以發(fā)現(xiàn)一些頁面操作發(fā)現(xiàn)不了的問題

          ③接口測(cè)試低成本高效益(底層的一個(gè)bug能夠引發(fā)上層8個(gè)左右bug,接口測(cè)試可以實(shí)現(xiàn)自動(dòng)化)

          ④不同于傳統(tǒng)的單元測(cè)試,接口測(cè)試是從用戶的角度對(duì)系統(tǒng)進(jìn)行全面的檢查

          1.6實(shí)現(xiàn)方式

          工具:fiddler、postman、jmeter;代碼:python+UnitTest框架+Requests框架

          1.7自動(dòng)化接口測(cè)試

          接口自動(dòng)化測(cè)試:借助工具、代碼,模擬客戶端發(fā)送請(qǐng)求給服務(wù)器,借助斷言自動(dòng)判斷 預(yù)期結(jié)果和實(shí)際結(jié)果是否一致。【是讓程序或工具代替人工自動(dòng)地完成對(duì)接口進(jìn)行測(cè)試的一種過程】

          二、HTTP協(xié)議

          (超文本傳輸協(xié)議,基于請(qǐng)求與響應(yīng)模式的,應(yīng)用層協(xié)議,也是互聯(lián)網(wǎng)上應(yīng)用最為廣泛的一種協(xié)議)【端口是用來找到應(yīng)用】

          2.1 協(xié)議:就是規(guī)則。要求通信的雙方必須嚴(yán)格遵守。

          2.2 特點(diǎn)

          ①支持客戶端/服務(wù)器模式 ②簡(jiǎn)單快速 ③靈活 ④無連接 ⑤無狀態(tài)

          2.3 URL(Uniform Resource Locator)統(tǒng)一資源定位符,是互聯(lián)網(wǎng)上標(biāo)準(zhǔn)資源的地址。HTTP使用URL來建立連接和傳輸數(shù)據(jù)。

          作用:在網(wǎng)絡(luò)環(huán)境中,唯一的定義一個(gè)數(shù)據(jù)資源

          2.4 URL語法格式(組成)【http:80;https:443】

          http[協(xié)議] :// xxxxx[域名] : xxxx[端口:0~65535] / xxxxxx[資源路徑] ? xx[k=value]&xx&x[查詢參數(shù)]

          協(xié)議:規(guī)定數(shù)據(jù)傳輸?shù)姆绞?/p>

          域名:在網(wǎng)絡(luò)環(huán)境中找到主機(jī) 用://與協(xié)議分隔

          端口(port)【常省略】:在網(wǎng)絡(luò)主機(jī)上,標(biāo)識(shí)一個(gè)進(jìn)程(運(yùn)行起來的應(yīng)用程序) 本地主機(jī)用PID標(biāo)識(shí) 用 :與域名分隔

          資源路徑:標(biāo)識(shí)網(wǎng)絡(luò)資源(文件、圖片、音視頻、變量.....) 用/與端口分隔

          查詢參數(shù):參數(shù)傳遞給資源路徑 用?與資源路徑分隔,內(nèi)部用&分隔

          【當(dāng)資源路徑?jīng)]有時(shí),可以認(rèn)為是“/”】

          2.5 HTTP請(qǐng)求【請(qǐng)求包;請(qǐng)求報(bào)文】

          1>作用:

          客戶端(app、瀏覽器),發(fā)送請(qǐng)求給服務(wù)器時(shí),使用的協(xié)議--http請(qǐng)求協(xié)議

          規(guī)定發(fā)送給服務(wù)器的數(shù)據(jù)傳輸?shù)恼Z法格式

          2>整體格式

          第一行:請(qǐng)求行:請(qǐng)求方法(空格)url(空格)協(xié)議版本

          第二行:請(qǐng)求頭:語法格式 【格式:key:value】

          user-agent:描述發(fā)送端的本地瀏覽器類型

          Content-Type:xxxx(描述請(qǐng)求體的數(shù)據(jù)類型)通常碰到form(表單類型)和json類型

          空行:代表http請(qǐng)求頭結(jié)束,請(qǐng)求體開始

          請(qǐng)求體:請(qǐng)求發(fā)送時(shí)攜帶的數(shù)據(jù)。 數(shù)據(jù)類型(Content-Type)的值【post、put(相當(dāng)于修改)有請(qǐng)求體,get、delete沒有請(qǐng)求體】

          3>fiddler抓包驗(yàn)證

          先清空fiddler--訪問網(wǎng)站--點(diǎn)開(一般第一條)請(qǐng)求--點(diǎn)擊【raw】

          4>請(qǐng)求行

          http請(qǐng)求方法(大小寫無所謂)【對(duì)應(yīng)數(shù)據(jù)庫增刪改查】

          GET:查詢

          POST:添加(常用在登錄)

          PUT:修改

          DELETE:刪除

          5>請(qǐng)求頭

          語法格式:k:v

          user-agent:產(chǎn)生請(qǐng)求瀏覽器類型

          Content-Type:請(qǐng)求體數(shù)據(jù)類型

          application/json:JSON數(shù)據(jù)格式(k:v)

          application/x-www-form-urlencoded:form表單數(shù)據(jù)


          6>請(qǐng)求體

          數(shù)據(jù)值的組織形式,受Content-Type的值影響

          k=v格式

          get、delete方法沒有請(qǐng)求體

          post、put方法有請(qǐng)求體

          2.6 HTTP響應(yīng)

          1>作用:服務(wù)器端,針對(duì)客戶端發(fā)送的http請(qǐng)求,回發(fā)響應(yīng)數(shù)據(jù)。 --http應(yīng)答

          規(guī)定回發(fā)給客戶端的數(shù)據(jù)組織格式

          2>整體格式【響應(yīng)包;響應(yīng)報(bào)文】

          響應(yīng)行(狀態(tài)行):協(xié)議版本(空格)狀態(tài)碼(空格)狀態(tài)描述【狀態(tài)碼和狀態(tài)描述捆綁,狀態(tài)碼對(duì)應(yīng)狀態(tài)描述】

          響應(yīng)頭:語法格式:k:v

          Content-Type:描述響應(yīng)體中數(shù)據(jù)類型

          空行:代表響應(yīng)頭結(jié)束

          響應(yīng)體:絕大多數(shù)情況不為空(請(qǐng)求成功:回發(fā)數(shù)據(jù),失敗:回發(fā)錯(cuò)誤數(shù)據(jù))

          數(shù)據(jù)類型受Content-Type值影響

          3>狀態(tài)碼【有三位數(shù)字組成,第一個(gè)數(shù)字定義響應(yīng)的類別】

          1xx:指示信息--表示請(qǐng)求已接收,等待繼續(xù)處理

          **2xx:成功--表示請(qǐng)求已被成功接收、理解、接受:eg:200、201

          3xx:重定向--待訪問的資源,需求重新指定路徑訪問。【要完成請(qǐng)求必須進(jìn)行更進(jìn)一步的操作】

          **4xx:客戶端錯(cuò)誤--請(qǐng)求有語法錯(cuò)誤或請(qǐng)求無法實(shí)現(xiàn) eg:404【請(qǐng)求文件不存在】/403【請(qǐng)求文件存在但拒絕被訪問,也就是說沒有權(quán)限訪問】

          5xx:服務(wù)器端錯(cuò)誤--服務(wù)器未能實(shí)現(xiàn)合法的請(qǐng)求

          4>狀態(tài)碼描述

          一般與狀態(tài)碼唯一對(duì)應(yīng)

          5>響應(yīng)頭

          語法格式:k:v

          Content-Type:值為響應(yīng)體的數(shù)據(jù)類型

          Content-Length:響應(yīng)體的大小【可不寫,瀏覽器自動(dòng)求取,一旦寫,必須準(zhǔn)確】

          6>響應(yīng)體(測(cè)試中的實(shí)際結(jié)果,預(yù)期結(jié)果從接口文檔中來)

          就是響應(yīng)的消息體,數(shù)據(jù)可以是普通文本、XML、JSON、HTML源碼

          三、接口測(cè)試風(fēng)格

          1>傳統(tǒng)風(fēng)格

          對(duì)用戶進(jìn)行操作的相關(guān)接口,包括增刪改查

          操作

          請(qǐng)求方式

          URL

          成功狀態(tài)

          查詢某個(gè)用戶

          GET/POST

          http://127.0.0.1:8080/myweb/user/getUser?id=1

          http://127.0.0.1:8080/myweb/user/getById?id=1

          http://127.0.0.1:8080/myweb/getUserById?id=1

          200

          查詢所有用戶

          GET/POST

          http://127.0.0.1:8080/myweb/user/getUserList

          http://127.0.0.1:8080/myweb/user/getUsers

          200

          添加用戶

          POST

          http://127.0.0.1:8080/myweb/user/addUser

          200

          修改用戶

          POST

          http://127.0.0.1:8080/myweb/user/updateUser

          200

          刪除用戶

          GET/POST

          http://127.0.0.1:8080/myweb/user/deleteUser?id=1

          200

          特點(diǎn):

          請(qǐng)求方法,只使用get和post即可

          URL不唯一,不重復(fù)。同一個(gè)操作可以對(duì)應(yīng)不同的URL

          狀態(tài)碼的使用較單一。200最常見

          2>RESTful風(fēng)格接口【一種軟件架構(gòu)風(fēng)格、設(shè)計(jì)風(fēng)格,而不是標(biāo)準(zhǔn),只是提供了一組設(shè)計(jì)原則和約束條件】

          REST:即(Representational State Transfer)的縮寫,詞組翻譯是“表現(xiàn)層狀態(tài)轉(zhuǎn)化”【同一URL,對(duì)應(yīng)的方法不同,對(duì)應(yīng)的操作也不同】,如果一個(gè)架構(gòu)符合REST原則,就稱它為RESTful架構(gòu)。

          操作

          請(qǐng)求方式

          URL

          成功狀態(tài)

          查詢某個(gè)用戶

          GET

          http://127.0.0.1:8080/myweb/users/1

          200

          查詢所有用戶

          GET

          http://127.0.0.1:8080/myweb/users

          200

          添加用戶

          POST

          http://127.0.0.1:8080/myweb/users

          201

          修改用戶

          PUT

          http://127.0.0.1:8080/myweb/users/1

          201

          刪除用戶

          DELETE

          http://127.0.0.1:8080/myweb/users/1

          204

          架構(gòu)特點(diǎn):

          1.每一個(gè)URL代表一種資源;

          2.客戶端和服務(wù)器之間,傳遞這種資源的某種表現(xiàn)層;

          3.客戶端通過四個(gè)HTTP動(dòng)詞,對(duì)服務(wù)器端資源進(jìn)行操作,實(shí)現(xiàn)“表現(xiàn)層狀態(tài)轉(zhuǎn)換”(數(shù)據(jù)的不同表現(xiàn)形式,圖像、文字表現(xiàn)同一個(gè)數(shù)據(jù)對(duì)象)

          4.接口之間傳遞的數(shù)據(jù)最常用格式為JSON。

          四、接口測(cè)試流程

          1. 需求分析:主要依據(jù)需求文檔(產(chǎn)品)
          2. 接口文檔解析:一般是由開發(fā)人員編寫的接口文檔(API文檔)
          3. 設(shè)計(jì)接口測(cè)試用例(根據(jù)接口文檔產(chǎn)生用例,送審)
          4. 執(zhí)行測(cè)試用例:使用接口測(cè)試工具實(shí)現(xiàn)(postman、jmeter);通過編寫代碼實(shí)現(xiàn)(python+requests+unittest)
          5. 接口缺陷的管理和跟蹤
          6. 生成測(cè)試報(bào)告
          7. 接口自動(dòng)化持續(xù)集成(可選)

          五、接口文檔的作用和展現(xiàn)形式

          5.1接口文檔

          1>接口文檔:又稱為API文檔,一般是由開發(fā)人員所編寫的,用來描述系統(tǒng)所提供接口信息的文檔。大家都根據(jù)這個(gè)接口文檔進(jìn)行開發(fā),并需要一直維護(hù)和遵守。

          2>作用

          1.能夠讓前端開發(fā)與后臺(tái)開發(fā)人員更好的配合,提高工作效率。(有一個(gè)統(tǒng)一參考的文件)

          2.項(xiàng)目選代或者項(xiàng)目人員更迭時(shí),方便后期人員查看和維護(hù)

          3.方便測(cè)試人員進(jìn)行接口測(cè)試

          1. 展現(xiàn)形式

          【錯(cuò)誤碼:不是錯(cuò)誤,與http狀態(tài)碼區(qū)分開,其實(shí)是狀態(tài)碼,描述狀態(tài)】

          形式:word文檔形式、Excel表格式形式、pdf文檔

          1. 結(jié)構(gòu)

          基本信息:

          Path:對(duì)應(yīng)url里的資源路徑(url前面的協(xié)議等在接口文檔的系統(tǒng)信息里呈現(xiàn))

          Method:PUT/POST/DELETE/GET

          接口描述:。。。。。

          請(qǐng)求參數(shù):

          Headers(請(qǐng)求頭):數(shù)據(jù)類型(k【Content-Type】:v【application/json】)

          Body(請(qǐng)求體):實(shí)現(xiàn)該接口使用的數(shù)據(jù)以及對(duì)應(yīng)類型。

          返回?cái)?shù)據(jù)(預(yù)期結(jié)果):成功和失敗的狀態(tài)碼

          狀態(tài)碼:200 成功:狀態(tài)碼200

          錯(cuò)誤碼(自定義狀態(tài)碼):碼值和描述信息 失敗:錯(cuò)誤碼(自定義狀態(tài)碼)

          5.2接口文檔解析

          接口文檔的解析本質(zhì):從接口文檔中,找出http請(qǐng)求所需要的數(shù)據(jù)信息,包括:

          請(qǐng)求方法URL【行里兩個(gè)】、請(qǐng)求頭(k:v)【Content-Type類型】、請(qǐng)求體【數(shù)據(jù):數(shù)據(jù)類型的名字和類型】(行頭體)、響應(yīng)狀態(tài)碼、描述。

          Eg:

          請(qǐng)求體:{“數(shù)據(jù)類型的名字,建議復(fù)制文檔里的不要用手敲”:“數(shù)據(jù)值,文檔中不知道,可找開發(fā)要”}

          Fiddler:

          K:v是json類型數(shù)據(jù)

          Raw項(xiàng):方法、url、請(qǐng)求頭、請(qǐng)求體

          接口用例設(shè)計(jì)

          6.1為什么要寫

          1.防止測(cè)試點(diǎn)漏測(cè)、條理清晰

          2.方便分配工作,評(píng)估工作量和時(shí)間

          3.面試使用

          6.2接口測(cè)試的測(cè)試點(diǎn)(測(cè)試維度)

          6.3功能測(cè)試

          1. 單接口功能

          手工測(cè)試中的單個(gè)業(yè)務(wù)模塊,一般對(duì)應(yīng)一個(gè)接口。

          Eg: 登錄業(yè)務(wù)-->登錄接口

          加入購物車業(yè)務(wù)-->加入購物車接口

          支付業(yè)務(wù)-->支付接口

          .........

          借助工具、代碼,繞開前端界面,組織接口所需要的數(shù)據(jù),展開接口測(cè)試。

          1. 業(yè)務(wù)場(chǎng)景功能

          按照用戶實(shí)際使用場(chǎng)景,梳理接口業(yè)務(wù)場(chǎng)景。

          組織業(yè)務(wù)場(chǎng)景時(shí),一般只需要做正向測(cè)試即可。(與手工一致)

          一般建議用最少的用例覆蓋最多的業(yè)務(wù)場(chǎng)景。

          Eg:登錄---搜索商品---加購物車---下單---支付---評(píng)價(jià)

          6.4性能測(cè)試

          1>響應(yīng)時(shí)長(zhǎng):發(fā)送請(qǐng)求,服務(wù)器多久回發(fā)響應(yīng)

          2>吞吐量:當(dāng)前的接口處理用戶的請(qǐng)求事物數(shù)量

          3>并發(fā)數(shù):多個(gè)用戶同時(shí)向接口發(fā)請(qǐng)求,比如淘寶秒殺

          4>服務(wù)器資源利用率:CPU、內(nèi)存、顯卡、網(wǎng)絡(luò)I/O、磁盤I/O

          6.5瀏覽器開發(fā)者工具

          瀏覽器的開發(fā)者工具:F12或右鍵檢查打開--->Network--->一定要選擇ALL--->關(guān)于登錄,可以在網(wǎng)站界面輸入好數(shù)據(jù),點(diǎn)擊登錄按鈕--->查看

          點(diǎn)擊Name下數(shù)據(jù)--->do_login(與登錄按鈕對(duì)應(yīng)):

          Headers【相當(dāng)于HTTP響應(yīng),組織形式不一樣,但是數(shù)據(jù)該有的都有】:

          General:表示總則;包括請(qǐng)求URL、請(qǐng)求方法、狀態(tài)碼(Status Code)、IP地址和端口號(hào)(Remote Address)

          Response Headers:表示響應(yīng)頭;數(shù)據(jù)以k:v形式組織

          Request Headers:表示請(qǐng)求頭;對(duì)應(yīng)HTTP請(qǐng)求頭里的信息;數(shù)據(jù)類型依然k:v形式

          Query String Parameters:表示查詢字符串參數(shù),對(duì)應(yīng)url后部分的查詢參數(shù)

          Form Data:表單數(shù)據(jù);比如登錄界面,這部分是登錄界面輸入的數(shù)據(jù)

          Payload:有一個(gè)view source,是請(qǐng)求體的數(shù)據(jù),可以直接復(fù)制json數(shù)據(jù)

          Response【查看服務(wù)器響應(yīng)返回的結(jié)果】

          6.6安全測(cè)試

          1>攻擊安全:由專業(yè)安全測(cè)試工程師完成;

          2>業(yè)務(wù)安全

          ①敏感數(shù)據(jù)是否加密:比如密碼

          ②SQL注入:

          輸入用戶名為:‘ or 1=1#,提示用戶名格式錯(cuò)誤,表示沒有SQL注入的漏洞

          ③其他

          6.7與手工測(cè)試區(qū)別

          1>手工測(cè)試測(cè)寫入到輸入框中的數(shù)據(jù)是否正確。接口測(cè)試測(cè)參數(shù)對(duì)應(yīng)的參數(shù)值是否正確,相當(dāng)于k:v。

          2>接口測(cè)試不單單針對(duì)參數(shù)值進(jìn)行測(cè)試,還可以針對(duì)參數(shù)本身進(jìn)行測(cè)試。比如測(cè)username本身,用uname:正確的用戶名去測(cè)試,看看能否通過。

          對(duì)于參數(shù)測(cè):

          ①正向參數(shù):

          必選參數(shù):所有的必填項(xiàng)都包含。

          組合參數(shù):所有的必填+任意一個(gè)或多個(gè)可選參數(shù)

          全部參數(shù):所有的必填+所有的可選參數(shù)

          ②反向參數(shù):

          多參:多出一個(gè)或多個(gè)必選參數(shù)(可以任意指定)

          少參:缺少一個(gè)或者多個(gè)必選參數(shù)

          無參:沒有必選參數(shù)

          錯(cuò)誤參數(shù):參數(shù)名輸入錯(cuò)誤

          6.8接口測(cè)試文檔要素

          編號(hào)、用例名稱(標(biāo)題)、模塊、優(yōu)先級(jí)、預(yù)置條件、請(qǐng)求方法、URL、請(qǐng)求頭、請(qǐng)求體(請(qǐng)求數(shù)據(jù))、預(yù)期結(jié)果

          URL列:寫完整URL或者寫{協(xié)議+域名}/文檔里的path內(nèi)容【path寫明確,協(xié)議和域名可寫成文字,以防后期協(xié)議和域名修改,就不用大篇幅修改】

          登錄界面

          1. 操作成功不代表登錄成功,只能說http請(qǐng)求已經(jīng)被服務(wù)端處理了。會(huì)出現(xiàn)狀態(tài)碼
          2. 預(yù)期結(jié)果包括狀態(tài)碼和描述信息;data數(shù)據(jù)包括當(dāng)前用戶登錄的身份,下次只要核對(duì)data的值,登錄成功會(huì)產(chǎn)生令牌(token,隔段時(shí)間會(huì)變)數(shù)據(jù)(data的值)表明用戶已經(jīng)登錄進(jìn)去了

          登錄里的用戶名未注冊(cè)就是不存在

          3>數(shù)值部分和手工測(cè)試一樣,參數(shù)是接口特有的。

          用戶名和密碼為空不能想當(dāng)然認(rèn)為都是用戶名或密碼錯(cuò)誤,要去實(shí)踐。

          登錄的信息都是去數(shù)據(jù)庫中比對(duì),如果特殊字符等在數(shù)據(jù)庫中不允許出現(xiàn),就不用做此類反向測(cè)試。要在數(shù)據(jù)庫中組織出不符合的數(shù)據(jù),測(cè)開發(fā)在接收數(shù)據(jù)的時(shí)候,不能依托數(shù)據(jù)庫,而是依托開發(fā)的代碼有沒有校驗(yàn)出來,不符合規(guī)范的手機(jī)號(hào)是否能登錄成功。

          總結(jié):在接口測(cè)試用例中,對(duì)于k:v,考慮k的正反向,v保證正確;考慮v的正反向,k保證正確。

          業(yè)務(wù)場(chǎng)景功能

          8.1分析測(cè)試點(diǎn)

          Eg:針對(duì)“員工管理”業(yè)務(wù)場(chǎng)景:登錄---添加員工---查詢員工(看看是否添加成功)---修改員工---再次查詢(看看修改成功)---刪除員工---查詢員工(看看是否刪除)【相當(dāng)于把多個(gè)模塊接口串起來,用最少的用例盡可能的覆蓋所有接口】

          8.2添加用戶【測(cè)校驗(yàn)的情況:正確、錯(cuò)誤、重復(fù)】

          請(qǐng)求方法:post

          URL:

          請(qǐng)求頭:

          請(qǐng)求體:

          返回?cái)?shù)據(jù):

          8.3查詢員工【測(cè)校驗(yàn)的情況:正確、空值、錯(cuò)誤值】

          8.4修改員工

          8.5刪除員工

          POSTMAN

          1. 官網(wǎng)下載postman:https://app.getpostman.com/app/download/win64
          2. 下載node.js:https://nodejs.org/zh-cn/download/,為了安裝newman
          3. 安裝newman:npm install -g newman
          4. 為newman安裝newman-reporter-html【newman是postman插件,newman-reporter-html是newman的插件】,安裝命令:npm install -g newman-reporter-html

          9.1開發(fā)者工具

          Headers請(qǐng)求方法、request URL、request headers中的content-type【代表數(shù)據(jù)類型,后面的utf可以不管】、Form data【請(qǐng)求體,k:v對(duì)】

          Preview返回?cái)?shù)據(jù)中看不懂的字符,在preview里能找到

          Response:看返回?cái)?shù)據(jù)【漢字的轉(zhuǎn)碼在preview里】

          9.2Postman使用

          Postman:

          Headers:填寫content-type的k:v值

          Body:下拉框選項(xiàng)選擇content-type中的v項(xiàng),然后填入請(qǐng)求體中的k:v對(duì),是json就選擇raw【原始】

          Send完看響應(yīng)數(shù)據(jù),在body下,選擇pretty,把html改成json,就可以看到返回的結(jié)果了

          結(jié)果:

          階段目標(biāo)劃分

          Postman管理測(cè)試用例collections

          1. 創(chuàng)建collections
          2. Add request:創(chuàng)建用例,添加請(qǐng)求

          點(diǎn)擊sava或ctrl+s,小紅點(diǎn)就沒有了

          1. Add folder:創(chuàng)建子目錄

          用例集導(dǎo)出、導(dǎo)入

          1. export:導(dǎo)出,在用例集名稱右側(cè)的三點(diǎn)中,一般默認(rèn)選項(xiàng)導(dǎo)出
          2. 文件名后綴不可改,文件名不建議修改,只有第一段文字可修改,接口集成時(shí),不可以用中文命名
          3. Import:導(dǎo)入,file->upload files->選文件位置

          Postman斷言

          1. 斷言:讓程序判斷預(yù)期結(jié)果與實(shí)際結(jié)果是否一致。
          2. 特點(diǎn):postman斷言是使用JavaScript語言編寫的,寫在Tests標(biāo)簽頁里【對(duì)應(yīng)框上面有Tests選項(xiàng)】
          3. postman常用斷言【在<中選擇對(duì)應(yīng)的就可以,代碼自動(dòng)生成】

          總體步驟:

          • 在Tests標(biāo)簽中,選擇斷言方法適當(dāng)調(diào)整test()方法參數(shù)1,和匿名函數(shù)中的預(yù)期結(jié)果點(diǎn)擊send按鈕,發(fā)送請(qǐng)求,執(zhí)行斷言代碼。查看斷言結(jié)果

          **3.1斷言響應(yīng)狀態(tài)碼

          選擇:Status code:code is 200

          詳情:pm.test("Status code is 200", function () {

          pm.response.to.have.status(200);

          });

          解釋:

          pm:代表postman的一個(gè)實(shí)例【類下面的一個(gè)對(duì)象】

          test():是pm實(shí)例的一個(gè)方法。有兩個(gè)參數(shù)

          參數(shù)1:在斷言成功后,給出的文字提示,可以修改。"Status code is 200"

          參數(shù)2:匿名函數(shù),function () {pm.response.to.have.status(200);}

          function代表函數(shù),后面應(yīng)該放函數(shù)名,但是沒有,所以是匿名函數(shù);

          response代表響應(yīng)體,to.have應(yīng)該有

          整句話表示:postman的響應(yīng)結(jié)果中應(yīng)該包含狀態(tài)碼200

          200是預(yù)期結(jié)果

          斷言的結(jié)果在Tests項(xiàng)下Test Results,看到PASS和Status code is 200【對(duì)應(yīng)斷言成功后的描述】

          3.2斷言響應(yīng)體是否包含某個(gè)字符串

          選擇:Response body:Contains string

          詳情:pm.test("Body matches string", function () {

          pm.expect(pm.response.text()).to.include("string_you_want_to_search");

          });

          解釋:預(yù)期結(jié)果用返回體內(nèi)的value值,推薦用message的value

          3.3斷言響應(yīng)體是否等于某個(gè)字符串(對(duì)象)【json花括號(hào)括起來是對(duì)象,中括號(hào)括起來是數(shù)組】

          選擇:Response body:Is equal to a string

          詳情:pm.test("Body is correct", function () {

          pm.response.to.have.body("response_body_string");

          });

          解釋:通常data對(duì)應(yīng)令牌數(shù)據(jù)會(huì)不停地改變,這個(gè)字符串是對(duì)返回的全部字符串進(jìn)行判斷,一旦有數(shù)據(jù)不停變化時(shí),斷言不通過。

          **3.4斷言JSON數(shù)據(jù)

          選擇:Response body:JSON value check

          詳情:pm.test("Your test name", function () {

          var jsonData=pm.response.json();

          pm.expect(jsonData.value).to.eql(100);

          });

          解釋:

          var jsonData=pm.response.json(); var jsonData用js語法定義一個(gè)變量;jsonData是變量名;pm.response.json()代表響應(yīng)的json結(jié)果,就是響應(yīng)的數(shù)據(jù)

          pm.expect(jsonData.value).to.eql(100); 預(yù)期json結(jié)果值等于100相同,value對(duì)應(yīng)響應(yīng)體中的key


          3.5斷言相應(yīng)頭【返回的Headers里】

          選擇:Response headers:Content-Type header check

          詳情:pm.test("Content-Type is present", function () {

          pm.response.to.have.header("Content-Type");

          });

          解釋:響應(yīng)頭中包含Content-Type;可以判定k:v是否正確,斷言響應(yīng)頭所對(duì)應(yīng)的value,直接(k,v)

          示例:pm.test("Content-Type is present", function () {

          pm.response.to.have.header("Content-Type","application/json");

          });【在響應(yīng)的headers中,添加響應(yīng)頭中的key對(duì)應(yīng)的value判定,用,分隔】

          Postman斷言工作原理

          全局變量和環(huán)境變量

          15.1概念

          全局變量:全局變量是全局唯一的,不可重復(fù)定義的變量

          環(huán)境變量:一個(gè)變量只能屬于某個(gè)環(huán)境,在某一個(gè)環(huán)境中變量不可重復(fù)定義;在環(huán)境與環(huán)境之間可以定義重復(fù)的變量;一個(gè)環(huán)境可以包含多個(gè)環(huán)境變量;常見環(huán)境分類:開發(fā)環(huán)境、測(cè)試環(huán)境、生產(chǎn)環(huán)境【一個(gè)項(xiàng)目生產(chǎn)部署上線】

          15.2設(shè)置變量

          全局變量:

          • 手動(dòng)設(shè)置代碼設(shè)置:pm.globals.set(“var_name”,value);【變量名必須要雙引號(hào)】

          環(huán)境變量:

          1. 手動(dòng)設(shè)置
          2. 代碼設(shè)置:pm.environment.set(“var_name”,value);

          15.3獲取變量【請(qǐng)求參數(shù)是從params、headers、url中拿出來的,只要從界面中獲取的[相當(dāng)于從兩個(gè)請(qǐng)求的postman界面中獲取的];請(qǐng)求參數(shù)只能用在請(qǐng)求參數(shù)中,不可以用在代碼區(qū)域{tests、請(qǐng)求前置腳本},可用在params、headers、bodys

          全局變量:

          • 請(qǐng)求參數(shù)中獲取:{{var_name}}代碼中獲取:var value=pm.globals.get(“var_name”);【取的時(shí)候只要變量名】

          環(huán)境變量:

          1. 請(qǐng)求參數(shù)中獲取:{{var_name}}
          2. 代碼中獲取:var value=pm.environment.get(“var_name”);【取的時(shí)候只要變量名】

          【獲取都用要一個(gè)變量去接收,多級(jí)的要一級(jí)一級(jí)取】

          請(qǐng)求前置腳本

          16.1地位:在send按鈕點(diǎn)擊后,請(qǐng)求前置腳本代碼,第一時(shí)間被執(zhí)行。在postman內(nèi)部實(shí)際http請(qǐng)求之前。

          16.2時(shí)間戳

          概念:對(duì)應(yīng)絕對(duì)時(shí)間----從1970年1月1日00:00:00到現(xiàn)在所經(jīng)歷的秒數(shù)

          16.3案例

          調(diào)用百度首頁接口,傳時(shí)間戳給服務(wù)器

          實(shí)現(xiàn)步驟:

          ①拿到時(shí)間戳寫入全局變量

          //拿到時(shí)間戳數(shù)據(jù)值

          var timestamp = new Date().getTime()

          //將時(shí)間戳設(shè)置到全局變量中

          pm.globals.set("glb_timestamp",timestamp)

          ②點(diǎn)擊send按鈕,發(fā)送請(qǐng)求。請(qǐng)求發(fā)送前執(zhí)行上述代碼,寫入全局變量

          ③查看寫入的變量:點(diǎn)擊眼睛圖標(biāo)

          ④在請(qǐng)求參數(shù)(界面)中,使用全局變量。{{var_name}}【params是查詢參數(shù)】

          ⑤在postman控制臺(tái),查看發(fā)送的http請(qǐng)求

          【send發(fā)送請(qǐng)求之前會(huì)執(zhí)行請(qǐng)求前置腳本,寫進(jìn)全局變量當(dāng)中,再發(fā)送請(qǐng)求】

          Postman關(guān)聯(lián)

          17.1介紹:應(yīng)用于多個(gè)http請(qǐng)求之間,有數(shù)據(jù)關(guān)聯(lián)、或依賴關(guān)系時(shí)。

          17.2實(shí)現(xiàn)步驟

          A接口依賴B接口的數(shù)據(jù)

          ①向B接口發(fā)送http請(qǐng)求,獲取數(shù)據(jù)

          ②將數(shù)據(jù)保存至全局變量(環(huán)境變量)中

          ③A接口獲取全局變量(環(huán)境變量)中數(shù)據(jù)值,進(jìn)行使用

          17.3案例

          請(qǐng)求獲取天氣接口,提取響應(yīng)結(jié)果中的城市,將城市名,給百度搜索接口使用

          ①發(fā)送天氣接口請(qǐng)求,在天氣接口的Tests中獲取城市名,再把城市名寫入

          //獲取全部響應(yīng)結(jié)果

          var jsondate=pm.response.json()

          //從響應(yīng)結(jié)果中,獲取城市名

          var city=jsondate.一級(jí)一級(jí)往下引用k名

          //將城市名寫入到全局變量

          pm.globals.set(“city”,city)

          【點(diǎn)擊send按鈕,發(fā)送請(qǐng)求,查看設(shè)置的全局變量。點(diǎn)擊小眼睛,看全局變量名和全局變量值】

          //修改百度搜索請(qǐng)求,使用全局變量,按城市名進(jìn)行搜索

          Postman測(cè)試報(bào)告

          18.1批量執(zhí)行用例集

          Data:引入外部文件

          18.2生成測(cè)試報(bào)告(newman)【在dos界面】

          1.先把用例集執(zhí)行,run

          2.導(dǎo)出用例集

          3.生成測(cè)試報(bào)告

          ①{ newman run 測(cè)試腳本文件【導(dǎo)出的json文件】}[可單獨(dú)執(zhí)行] -e 環(huán)境變量文件【沒有環(huán)境變量就省略】 -d 測(cè)試數(shù)據(jù)文件 -r html【必寫】 --reporter-html-export report.html【報(bào)告名稱,report名可以修改】

          Postman讀取外部數(shù)據(jù)文件(參數(shù)化)

          比如:登錄接口,測(cè)一個(gè)用戶,請(qǐng)求體的數(shù)據(jù)是寫死的,要是測(cè)1000個(gè)用戶,需要用到參數(shù)化】

          【當(dāng)http請(qǐng)求,使用的數(shù)據(jù)有較高相似度時(shí),相同的請(qǐng)求時(shí),考慮使用參數(shù)化(將數(shù)據(jù)組織到數(shù)據(jù)文件中)】

          19.1數(shù)據(jù)文件簡(jiǎn)介

          CSV:

          優(yōu)點(diǎn):數(shù)據(jù)組織形式簡(jiǎn)單,適用于大量數(shù)據(jù)的場(chǎng)合

          缺點(diǎn):不支持bool類型數(shù)據(jù)(數(shù)據(jù)被postman讀入后,自動(dòng)添加“”包裹bool值);不支持多參、少參、無參、錯(cuò)誤參數(shù)的接口測(cè)試;不支持復(fù)雜數(shù)據(jù)類型(如嵌套字典、列表)

          【數(shù)值直接拿去用,非數(shù)值都加上“”】

          JSON:

          優(yōu)點(diǎn):支持bool類型;支持多參、少參、無參、錯(cuò)誤參數(shù)的接口測(cè)試;支持復(fù)雜數(shù)據(jù)類型(如嵌套字典、列表)

          缺點(diǎn):對(duì)于相同的數(shù)據(jù)量,JSON數(shù)據(jù)文件大小要遠(yuǎn)大于CSV文件

          19.2導(dǎo)入外部數(shù)據(jù)文件

          CSV:【一定要utf8編碼】

          ①創(chuàng)建XXX.CSV數(shù)據(jù)文件

          ②將數(shù)據(jù)寫入到CSV文件中:第一行寫入的是數(shù)據(jù)對(duì)應(yīng)的字段名;從第二行向后依次是對(duì)應(yīng)的數(shù)值,數(shù)據(jù)間用英文,分隔

          ③在Postman中,選中使用數(shù)據(jù)文件的用例集,導(dǎo)入數(shù)據(jù)文件【run->data:select file->選擇導(dǎo)入文件->通過preview預(yù)覽按鈕,校驗(yàn)數(shù)據(jù)文件是否正確】

          JSON:【可在json.cn網(wǎng)站里編寫,編寫好復(fù)制粘貼到記事本打開的json文件中】

          ①創(chuàng)建XXX.JSON數(shù)據(jù)文件

          ②在數(shù)據(jù)文件中,按json語法寫入json數(shù)據(jù)。Postman要求,json格式的數(shù)據(jù)文件,數(shù)據(jù)內(nèi)容的最外層,必須是[ ]。內(nèi)部所有的數(shù)據(jù)用{ }存儲(chǔ)

          ③在Postman中,選中使用數(shù)據(jù)文件的用例集,導(dǎo)入數(shù)據(jù)文件【run->data:select file->選擇導(dǎo)入文件->通過preview預(yù)覽按鈕,校驗(yàn)數(shù)據(jù)文件是否正確】

          建議書寫json數(shù)據(jù)時(shí),無論是不是字符串,都可以用” ”包裹value值

          19.3讀取數(shù)據(jù)文件數(shù)據(jù)

          1.方法

          ①請(qǐng)求參數(shù)(請(qǐng)求行、請(qǐng)求頭、請(qǐng)求體)中,使用數(shù)據(jù)文件中的數(shù)據(jù)

          使用{{}}包裹c(diǎn)sv文件字段名或json文件中的key

          ②代碼(斷言、請(qǐng)求前置腳本)中,使用數(shù)據(jù)文件中的數(shù)據(jù)

          需要借助postman提供的關(guān)鍵字data點(diǎn)【.】csv文件字段名或json文件中的key

          【send不能讀外部數(shù)據(jù)文件,用到外部數(shù)據(jù)文件了,讀取要進(jìn)入到run里,通過run參數(shù)化用例集的按鈕批量執(zhí)行。如果有異常,借助控制臺(tái)。】

          小結(jié):借助數(shù)據(jù)文件,實(shí)現(xiàn)“數(shù)據(jù)驅(qū)動(dòng)”。有多少條數(shù)據(jù),對(duì)應(yīng)就有多少個(gè)http請(qǐng)求。

          19.4生成測(cè)試報(bào)告

          步驟:

          ①批量執(zhí)行測(cè)試用例(借助數(shù)據(jù)文件)

          ②導(dǎo)出測(cè)試用例集(建議與數(shù)據(jù)文件放在一起)

          ③執(zhí)行生成測(cè)試報(bào)告的命令

          Newman run 用例集名稱.json -d 數(shù)據(jù)文件名.csv/.json -r html --reporter-html-export 報(bào)告名稱.html

          項(xiàng)目環(huán)境說明

          拿到一個(gè)項(xiàng)目,要對(duì)項(xiàng)目整體有個(gè)認(rèn)識(shí):熟悉項(xiàng)目的功能;了解項(xiàng)目組織架構(gòu)和相應(yīng)技術(shù)。

          20.1功能模塊:XXXXXX【模塊功能列出】

          20.2技術(shù)棧

          前端:頁面顯示........

          后端:spring全家桶;mysql【實(shí)現(xiàn)數(shù)據(jù)持久化存儲(chǔ),斷電也不會(huì)丟】+redis【緩存存儲(chǔ)數(shù)據(jù),讀取快】+rabbitmq【消息隊(duì)列,完成數(shù)據(jù)通信】

          20.3技術(shù)架構(gòu)圖(比較詳細(xì)展開描述技術(shù)棧)

          20.4初始化項(xiàng)目環(huán)境(利用postman)

          1. 新建用例集(不同的模塊對(duì)應(yīng)添加子目錄)
          2. 創(chuàng)建環(huán)境變量(選擇Enviroments->create enviroment)

          ①先創(chuàng)建環(huán)境,給環(huán)境取名【測(cè)試、開發(fā)、生成】

          ②initial value:在外部數(shù)據(jù)文件中使用,current value:在postman中使用

          【注意】:設(shè)置了環(huán)境,在執(zhí)行用例的時(shí)候要選擇對(duì)應(yīng)環(huán)境

          20.5數(shù)據(jù)依賴

          1.登錄成功,返回的“令牌”,被增刪改查功能接口依賴

          2.添加完的數(shù)據(jù)id,會(huì)被查、改、刪依賴

          【借助關(guān)聯(lián)和環(huán)境變量實(shí)現(xiàn)】

          20.6提取令牌

          1.登錄完成,返回data,不是完整令牌,缺少前綴

          2.實(shí)現(xiàn):

          ①發(fā)送http登錄請(qǐng)求,在響應(yīng)體中得到data值

          var json_data = pm.response.json()

          var env = json_data.data.token

          ②將data值拼接“Bearer”和“空格”,組成一個(gè)合法令牌

          pm.environment.set("env","Bearer"+" "+env)

          ③將令牌寫入環(huán)境變量中。(在Tests中通過代碼寫入)

          20.7生成測(cè)試報(bào)告

          1.在environment中有環(huán)境,要先導(dǎo)出環(huán)境

          2.將環(huán)境文件與測(cè)試用例集放置到同一目錄下

          3.執(zhí)行命令

          663


          主站蜘蛛池模板: 国产乱人伦精品一区二区在线观看| 国产大秀视频在线一区二区| 国产手机精品一区二区| 国产精品伦子一区二区三区| 蜜臀AV免费一区二区三区| 视频一区二区三区免费观看| 国产99视频精品一区| 久久国产精品免费一区| 日韩精品一区二区三区国语自制| 国产免费一区二区三区在线观看| 日本一区二区三区不卡视频中文字幕| 亚洲Av无码一区二区二三区| 色窝窝无码一区二区三区色欲| 国产一区二区三区在线视頻| 精品一区二区三区四区电影| 无码少妇丰满熟妇一区二区| 人妻久久久一区二区三区| 亚欧色一区W666天堂| 国产午夜精品免费一区二区三区 | 亚洲AV无码一区二区大桥未久| 精品一区二区久久| 亚洲AV无码第一区二区三区| 国产综合无码一区二区三区| 自慰无码一区二区三区| 中文无码AV一区二区三区| 国产无码一区二区在线| 久久精品一区二区三区中文字幕| 一区二区三区电影网| 久久精品无码一区二区日韩AV| 精品国产一区二区三区久久蜜臀| 久久精品国产第一区二区| 伊人激情AV一区二区三区| 一区二区视频在线| 中文字幕av一区| 波多野结衣一区二区免费视频| 国产一区二区免费视频| 美女福利视频一区| 精品国产AV无码一区二区三区| 国产主播福利一区二区| 国产精品一区二区香蕉| 波多野结衣一区在线|