解鎖數據潛力:信息抽取、數據增強與UIE的完美融合

解鎖數據潛力:信息抽取、數據增強與UIE的完美融合

1.信息抽取(Information Extraction)

1.1 IE簡介

信息抽取是 NLP 任務中非常常見的一種任務,其目的在于從一段自然文本中提取出我們想要的關鍵信息結構。

舉例來講,現在有下面這樣一個句子:

新東方烹飪學校在成都。

我們想要提取這句話中所有有意義的詞語,例如:

機構新東方烹飪學校
城市成都

這個關鍵詞提取任務就叫做**命名實體識別(Named Entity Recognition, NER)**任務,文中的「新東方烹飪學校」和「成都」就被稱為實體(Entity)。

如果我們還想進一步的知道這些詞語之間的關系,例如:

實體 1關系名實體 2
新東方烹飪學校所在地成都

這種提取實體之間關系的任務就叫做**關系抽取(Relation Extraction, RE)**任務。

1.2 信息抽取的幾種方法

1.2.1 序列標注(Sequence Labeling)

序列標注通常是指對文中的每一個字(以下簡稱 token)進行分類,即本質是 token classification 任務。

我們對第一小節中的例子做序列標注任務,得到的結果如下:

...
B - 機構I - 機構I - 機構 * NI - 機構I - 機構OB - 城市I - 城市

可以看到,我們對句子中的每一個字(token)都打上了一個類別標簽,我們期望模型要做的事就是去學會每一個字所屬的類別是什么。

Note: 這里用的標注方法是「BIO 標記法」,其中「B-」代表該位置 token 是某一個實體詞語(span)的起始 token;「I-」代表該位置 token 處于某一個詞語的中間(或結尾),「O」則代表該位置 token 不在任何一個實體詞語中。除了「BIO 標記法」外,還有許多其他的標注方式(如 BIOES 等),其本質思路都很類似。

1.2.2 指針網絡(Pointer Network)

序列標注模型有一個天然的缺陷,無法解決解決實體重疊(overlap)的問題。

舉例來講,如果今天我們不僅要提取「機構」,還同時要提取「機構類型」,那么我們期望的提取結果應該為:

機構新東方烹飪學校
機構類型學校
城市成都

可以看到,對于「學校」這兩個字,即屬于「新東方烹飪學校」(機構)這個詞,也存在于「學校」(機構類型)這個詞,那我們在給這兩個字打標簽的時候,究竟應該打成哪個類別呢?

B - 機構I - 機構I - 機構OB - 城市I - 城市

由此我們可以看到,因為在進行分類時我們通常對一個字(token)只賦予一個標簽,這就導致了 token classification 不能很好的解決實體重疊(一字多標簽)的復雜情況。

Note: 存在一些技巧可以解決該問題,例如可以從單字單分類(CE)衍生到單字多分類(BCE),這里不展開討論。

指針網絡(Pointer Network)通過分別對每一個實體單獨做預測來解決了實體之前的重疊沖突問題。

例如,我們現在要同時預測「機構」和「機構類型」這兩個實體,那么我們就可以設計一個多頭網絡(Multi-Head)來分別預測這兩個實體的實體詞。

其中,

「機構」實體頭中「起始」向量代表這一句話中是「機構」詞語的首字(例子中為「新」);

「機構」實體中「結束」向量代表這一句話中時「機構」詞語的尾字(例子中為「校」)。

通過「起始」和「結束」向量中的首尾字索引就能找到對應實體的詞語。

可以看到,通過構建多頭的任務,指針網絡能夠分別預測「機構」和「機構類型」中的實體詞起始 / 終止位置,即「學校」這個詞語在兩個任務層中都能被抽取出來。

1.3. UIE —— 基于 prompt 的指針網絡

1.3.1 UIE 中的 prompt 是什么?

多頭指針網絡能夠很好的解決實體重疊問題,但缺點在于:不夠靈活。

假定今天我們已經通過指針網絡訓練好了一個提取「機構」、「機構類型」的模型,即將交付時甲方突然提出一個新需求:我們想再多提取一個「機構簡稱」的屬性。

草(一種植物)。

從 2.2 節中的示意圖中我們可以看到,每一個實體類型會對應一個單獨的網絡頭。

這就意味著我們不僅需要重標數據,還需要為新屬性添加一個新的網絡頭,即模型結構會隨著實體類型個數改變而發生變化。

那,能不能有一種辦法去固定住模型的結構,不管今天來多少種類型要識別都能使用同樣的模型結構完成呢?

我們思考一下,模型結構變化的部分是和實體類型強綁定的「頭」部分。

而不同「頭」之間結構其實是完全一樣的:一個「起始」向量 + 一個「終止」向量。

既然「頭」結構完全一樣,我們能不能干脆直接使用一個「頭」去提取不同實體類型的信息呢?

不同「頭」之間的區別在于它們關注的信息不同:「機構頭」只關注「機構」相關的實體詞,「城市頭」只關注「城市」相關的實體詞。

那么我們是不是可以直接在模型輸入的時候就告訴模型:我現在需要提取「某個頭」的信息。

這個用來告訴模型做具體任務的參數就叫 prompt,我們把它拼在輸入中一并喂給模型即可。

通過上圖可以看到,我們將不同的「實體類型」作為 prompt 參數喂給模型,用于「激活」模型參數跟當前「實體類型」相關的參數,從而輸出不同的抽取結果。

Note: 「通過一個輸入參數去激活一個大模型中的不同參數,從而完成不同任務的思路」并不是首次出現,在 meta-learning 中也存在相關的研究,這里的 prompt 參數和 meta-parameter 有著非常類似的思路。

通過引入 prompt,UIE 也能很方便的解決實體之間的關系抽取(Relation Extraction)任務,例如:

1.3.2 UIE 的實現

看完了基本思路,我們來一起看看 UIE 是怎么實現的吧。

  1. 模型部分

UIE 的模型代碼比較簡單,只需要在 encoder 后構建一個起始層和一個結束層即可:

class UIE(nn.Module):def __init__(self, encoder):"""init func.Args:encoder (transformers.AutoModel): backbone, 默認使用 ernie 3.0Reference:https://github.com/PaddlePaddle/PaddleNLP/blob/a12481fc3039fb45ea2dfac3ea43365a07fc4921/model_zoo/uie/model.py"""super().__init__()self.encoder = encoderhidden_size = 768self.linear_start = nn.Linear(hidden_size, 1)self.linear_end = nn.Linear(hidden_size, 1)self.sigmoid = nn.Sigmoid()def forward(self,input_ids: torch.tensor,token_type_ids: torch.tensor,attention_mask=None,pos_ids=None,) -> tuple:"""forward 函數,返回開始/結束概率向量。Args:input_ids (torch.tensor): (batch, seq_len)token_type_ids (torch.tensor): (batch, seq_len)attention_mask (torch.tensor): (batch, seq_len)pos_ids (torch.tensor): (batch, seq_len)Returns:tuple:  start_prob -> (batch, seq_len)end_prob -> (batch, seq_len)"""sequence_output = self.encoder(input_ids=input_ids,token_type_ids=token_type_ids,position_ids=pos_ids,attention_mask=attention_mask,)["last_hidden_state"]start_logits = self.linear_start(sequence_output)       # (batch, seq_len, 1)start_logits = torch.squeeze(start_logits, -1)          # (batch, seq_len)start_prob = self.sigmoid(start_logits)                 # (batch, seq_len)end_logits = self.linear_end(sequence_output)           # (batch, seq_len, 1)end_logits = torch.squeeze(end_logits, -1)              # (batch, seq_len)end_prob = self.sigmoid(end_logits)                     # (batch, seq_len)return start_prob, end_prob
  1. ** 訓練部分**

訓練部分主要關注一下 loss 的計算即可。

由于每一個 token 都是一個二分類任務,因此選用 BCE Loss 作為損失函數。

分別計算起始 / 結束向量的 BCE Loss 再取平均值即可,如下所示:

criterion = torch.nn.BCELoss()
...start_prob, end_prob = model(input_ids=batch['input_ids'].to(args.device),token_type_ids=batch['token_type_ids'].to(args.device),attention_mask=batch['attention_mask'].to(args.device))
start_ids = batch['start_ids'].to(torch.float32).to(args.device)    # (batch, seq_len)
end_ids = batch['end_ids'].to(torch.float32).to(args.device)        # (batch, seq_len)
loss_start = criterion(start_prob, start_ids)                       # 起止向量loss -> (1,)
loss_end = criterion(end_prob, end_ids)                             # 結束向量loss -> (1,)
loss = (loss_start + loss_end) / 2.0                                # 求平均 -> (1,)
loss.backward()
...

該項目將借用transformers庫來實現paddlenlp版本中UIE,已實現:

  • UIE 預訓練模型自動下載

  • UIE Fine-Tuning 腳本

  • 信息抽取、事件抽取數據增強(DA)策略(提升 recall)

  • 信息抽取、事件抽取自分析負例生成(Auto Neg)策略(提升 precision)

  • 環境安裝

本項目基于 pytorch + transformers 實現,運行前請安裝相關依賴包:

pip install -r ../requirements.txttorch
transformers==4.22.1
datasets==2.4.0
evaluate==0.2.2
matplotlib==3.6.0
rich==12.5.1
scikit-learn==1.1.2
requests==2.28.1

2. 數據集準備

項目中提供了一部分示例數據,數據來自DuIE數據集中隨機抽取的100條,數據在 data/DuIE

若想使用自定義數據訓練,只需要仿照示例數據構建數據集構建prompt和content即可:

{"content": "譚孝曾是譚元壽的長子,也是譚派第六代傳人", "result_list": [{"text": "譚元壽", "start": 4, "end": 7}], "prompt": "譚孝曾的父親"}
{"content": "在圣保羅書院中學畢業后,曾鈺成又在中學會考及大學入學考試中名列全港前十名", "result_list": [{"text": "曾鈺成", "start": 12, "end": 15}], "prompt": "人物"}
{"content": "在圣保羅書院中學畢業后,曾鈺成又在中學會考及大學入學考試中名列全港前十名", "result_list": [{"text": "圣保羅書院", "start": 1, "end": 6}], "prompt": "曾鈺成的畢業院校"}
...

doccano導出數據如下所示:

{"text": "譚孝曾是譚元壽的長子,也是譚派第六代傳人", "entities": [{"id": 42517, "label": "人物", "start_offset": 0, "end_offset": 3, "text": "譚孝曾"}, {"id": 42518, "label": "人物", "start_offset": 4, "end_offset": 7, "text": "譚元壽"}], "relations": [{"id": 0, "from_id": 42517, "to_id": 42518, "type": "父親"}]}
...

可以運行 doccano.py 來將標注數據(doccano)轉換為訓練數據(prompt)。

3. 模型訓練

修改訓練腳本 train.sh 里的對應參數, 開啟模型訓練:

python train.py \--pretrained_model "uie-base-zh" \--save_dir "checkpoints/DuIE" \--train_path "data/DuIE/train.txt" \--dev_path "data/DuIE/dev.txt" \--img_log_dir "logs/" \--img_log_name "UIE Base" \--batch_size 32 \--max_seq_len 256 \--learning_rate 5e-5 \--num_train_epochs 20 \--logging_steps 10 \--valid_steps 100 \--device cuda:0

正確開啟訓練后,終端會打印以下信息:

...0%|          | 0/1 [00:00<?, ?ba/s]
100%|██████████| 1/1 [00:00<00:00,  6.91ba/s]
100%|██████████| 1/1 [00:00<00:00,  6.89ba/s]
global step 10, epoch: 1, loss: 0.00244, speed: 2.08 step/s
global step 20, epoch: 1, loss: 0.00228, speed: 2.17 step/s
global step 30, epoch: 1, loss: 0.00191, speed: 2.17 step/s
global step 40, epoch: 1, loss: 0.00168, speed: 2.14 step/s
global step 50, epoch: 1, loss: 0.00149, speed: 2.11 step/s
global step 60, epoch: 1, loss: 0.00138, speed: 2.15 step/s
global step 70, epoch: 2, loss: 0.00123, speed: 2.29 step/s
global step 80, epoch: 2, loss: 0.00112, speed: 2.12 step/s
global step 90, epoch: 2, loss: 0.00102, speed: 2.15 step/s
global step 100, epoch: 2, loss: 0.00096, speed: 2.15 step/s
Evaluation precision: 0.80851, recall: 0.84444, F1: 0.82609
best F1 performence has been updated: 0.00000 --> 0.82609
...

logs/UIE Base.png 文件中將會保存訓練曲線圖:

4. 模型預測

完成模型訓練后,運行 inference.py 以加載訓練好的模型并應用:

 if __name__ == "__main__":from rich import printsentences = ['譚孝曾是譚元壽的長子,也是譚派第六代傳人。']# NER 示例for sentence in sentences:ner_example(model,tokenizer,device,sentence=sentence, schema=['人物'])# SPO 抽取示例for sentence in sentences:information_extract_example(model,tokenizer,device,sentence=sentence, schema={'人物': ['父親'],})

NER和事件抽取在schema的定義上存在一些區別:

  • NER的schema結構為 List 類型,列表中包含所有要提取的 實體類型

  • 信息抽取的schema結構為 Dict 類型,其中 Key 的值是所有 主語Value 對應該主語對應的所有 屬性

  • 事件抽取的schema結構為 Dict 類型,其中 Key 的值是所有 事件觸發詞Value 對應每一個觸發詞下的所有 事件屬性

python inference.py

得到以下推理結果:

[+] NER Results: 
{'人物': ['譚孝曾', '譚元壽']
}[+] Information-Extraction Results: 
{'譚孝曾': {'父親': ['譚元壽']}, '譚元壽': {'父親': []}
}

5. 數據增強(Data Augmentation)

信息抽取/事件抽取的數據標注成本較高,因此我們提供幾種針對小樣本下的數據增強策略。

包括:

  • 正例:SwapSPO、Mask Then Fill

  • 負例:自分析負例生成(Auto Neg)

所有實現均在 Augmenter.py 中,為了便于使用,我們將其封裝為 web 服務以方便調用:

平臺使用 streamlit 搭建,因此使用前需要先安裝三方包:

pip install streamlit==1.17.0

隨后,運行以下命令開啟標注平臺:

streamlit run web_da.py --server.port 8904

在瀏覽器中訪問 ip + 端口(默認8904)即可打開標注平臺。


5.1 正例:SwapSPO 策略介紹

Swap SPO 是一種基于規則的簡單數據增強策略。

將同一數據集中相同 P 的句子分成一組,并隨機交換這些句子中的 S 和 O。

  • 策略輸入:

《夜曲》周杰倫 作曲 的一首歌。

《那些你很冒險的夢》 是當下非常火熱的一首歌,作曲林俊杰

  • Swap SPO 后的輸出:

《夜曲》 是當下非常火熱的一首歌,作曲周杰倫

5.2 正例:Mask Then Fill 策略介紹

Mask Then Fill 是一種基于生成模型的信息抽取數據增強策略。

對于一段文本,我們其分為「關鍵信息段」和「非關鍵信息段」,包含關鍵詞片段稱為「關鍵信息段」。

下面例子中標粗的為 關鍵信息片段,其余的為 非關鍵片段

大年三十 我從 北京 的大興機場 飛回成都

我們隨機 [MASK] 住一部分「非關鍵片段」,使其變為:

大年三十 我從 北京 [MASK] 飛回成都

隨后,將該句子喂給 filling 模型(T5-Fine Tuned)還原句子,得到新生成的句子:

大年三十 我從 北京 首都機場作為起點,飛回成都

Note: filling 模型是一個生成模型,示例中我們使用中文 T5 微調得到 DuIE 數據集下的模型(暫未開源)。您可以參考 這里 微調一個更適合您自己數據集下的 filling 模型,并將訓練好的模型路徑填寫至 web_da.py 中對應的位置。

...
device = 'cpu'                                                 # 指定設備
generated_dataset_height = 800                                 # 生成樣本展示高度                
max_show_num = 500                                             # 生成樣本最大保存行數
max_seq_len = 128                                              # 數據集單句最大長度
batch_size = 128                                               # 負例生成時的batch_sizefilling_model_path = '這里'                                     # fine-tuned filling model
...

5.3 負例:自分析負例生成(Auto Neg)策略介紹

信息抽取中通常會存在 P混淆 的問題,例如:

王文銘,76歲,是西紅市多魚村的大爺。

當我們同時生成 年齡去世年齡 這種非常近義的 prompt 進行抽取時,可能會出現 誤召回 的情況:

prompt: 王文銘的年齡     answer: 76-> 正確
prompt: 王文銘的去世年齡  answer: 76-> 錯誤

因此,我們基于一個已訓練好的模型,自動分析該模型在 訓練集 下存在哪些易混淆的 P,并為這些 P 自動生成負例,以提升模型的 Precision 指標。

將新生成的負例加入 原始訓練數據集,重新訓練模型即可。

5.4 各種 DA 策略的實驗效果

在 DuIE 100 條數據下測試,各種 DA 策略的效果如下所示(以下 P / R / F1 均取 F1 最高的 Epoch 指標):

DA PolicyPrecision(best)Recall(best)F1(best)
baseline0.80850.84440.8260
Swap SPO0.8409(↑)0.82220.8314(↑)
Auto Neg0.8297(↑)0.8666(↑)0.8478(↑)
Mask Then Fill0.9000(↑)1.0000(↑)0.9473(↑)
Mask Then Fill & Auto Neg0.9777(↑)0.9777(↑)0.9777(↑)
  • 原作者實現地址:https://github.com/universal-ie/UIE

  • paddle官方:https://github.com/PaddlePaddle/PaddleNLP/tree/develop/model_zoo/uie

  • https://github.com/HarderThenHarder/transformers_tasks/blob/main/UIE

更多優質內容請關注公號:汀丶人工智能;會提供一些相關的資源和優質文章,免費獲取閱讀。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/40086.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/40086.shtml
英文地址,請注明出處:http://en.pswp.cn/news/40086.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

從NLP到聊天機器人

一、說明 今天&#xff0c;當打電話給銀行或其他公司時&#xff0c;聽到電話另一端的機器人向你打招呼是很常見的&#xff1a;“你好&#xff0c;我是你的數字助理。請問你的問題。是的&#xff0c;機器人現在不僅可以說人類語言&#xff0c;還可以用人類語言與用戶互動。這是由…

windows權限維持—黃金白銀票據隱藏用戶遠控RustDeskGotoHttp

windows權限維持—黃金白銀票據&隱藏用戶&遠控&RustDesk&GotoHttp 1. 前置1.1. 初始問題1.1.1. 解決辦法 2. 隱藏用戶2.1. 工具原理2.2. 案例操作2.2.1. 單機添加用戶2.2.1.1. 工具添加用戶2.2.1.2. 工具查看隱藏用戶2.2.1.3. 本地查看隱藏用戶 2.2.2. 域內添加…

CentOS系統環境搭建(二)——Centos7設置時間為網絡時間

centos系統環境搭建專欄&#x1f517;點擊跳轉 Centos7設置時間為網絡時間 安裝ntpdate工具 yum -y install ntp ntpdate關閉ntpd service ntpd stop設置系統時間與網絡時間同步 ntpdate 0.asia.pool.ntp.org將系統時間寫入硬件時間 hwclock --systohc查看和設置時區 使…

NeuralNLP-NeuralClassifier的使用記錄(二),訓練預測自己的【中文文本多分類】

NeuralNLP-NeuralClassifier的使用記錄&#xff0c;訓練預測自己的【中文文本多分類】 數據準備&#xff1a; ? 與英文的訓練預測一致&#xff0c;都使用相同的數據格式&#xff0c;將數據通過代碼處理為JSON格式&#xff0c;以下是我使用的一種&#xff0c;不同的原數據情況…

java+springboot+mysql理發會員管理系統

項目介紹&#xff1a; 使用javaspringbootmysql開發的理發會員管理系統&#xff0c;系統包含超級管理員&#xff0c;系統管理員、客戶、發型師角色&#xff0c;功能如下&#xff1a; 超級管理員&#xff1a;管理員管理&#xff1b;會員管理&#xff1b;發型師管理&#xff1b…

如何保證數據庫的數據和Redis的數據一致性

實際項目中有可能會使用Redis緩存數據&#xff0c;那么在更新數據的時候如何保證數據庫中的數據和Redis緩存的數據一致&#xff0c;緩存同步策略的選擇是一個很重要的問題。網上有各種說法&#xff0c;大概總結有以下幾種&#xff0c;看看每種方案是否可行以及存在的問題和適用…

安裝軟件包

安裝軟件包 創建一個名為 /home/curtis/ansible/packages.yml 的 playbook : 將 php 和 mariadb 軟件包安裝到 dev、test 和 prod 主機組中的主機上 將 RPM Development Tools 軟件包組安裝到 dev 主機組中的主機上 將 dev 主機組中主機上的所有軟件包更新為最新版本 vim packa…

關于Firmae缺失binwalk模塊

問題 david707:~/FirmAE$ sudo ./run.sh -c weyow ./WAM_9900-20.06.03V.trx [*] ./WAM_9900-20.06.03V.trx emulation start!!! Traceback (most recent call last):File "./sources/extractor/extractor.py", line 19, in <module>import binwalk ModuleNot…

Android Studio調試的時候Logcat不顯示日志了

文章目錄 問題描述解決方案 問題描述 使用Log輸出日志的時候&#xff0c;Logcat窗口并沒有顯示日志。 去除所有的過濾條件之后&#xff0c;Logcat窗口仍然沒有一條消息。 解決方案 關閉Android Studio&#xff0c;重啟Android Studio即可。

Docker容器:docker基礎概述、安裝、網絡及資源控制

文章目錄 一.docker容器概述1.什么是容器2. docker與虛擬機的區別2.1 docker虛擬化產品有哪些及其對比2.2 Docker與虛擬機的區別 3.Docker容器的使用場景4.Docker容器的優點5.Docker 的底層運行原理6.namespace的六項隔離7.Docker核心概念 二.Docker安裝 及管理1.安裝 Docker1.…

【k8s】基于Prometheus監控Kubernetes集群安裝部署

目錄 基于Prometheus監控Kubernetes集群安裝部署 一、環境準備 二、部署kubernetes集群 三、部署Prometheus監控平臺 四、部署Grafana服務 五、grafana web操作 基于Prometheus監控Kubernetes集群安裝部署 一、環境準備 IP地址 主機名 組件 192.168.100.131 k8s-ma…

時序預測 | MATLAB實現WOA-CNN-GRU鯨魚算法優化卷積門控循環單元時間序列預測

時序預測 | MATLAB實現WOA-CNN-GRU鯨魚算法優化卷積門控循環單元時間序列預測 目錄 時序預測 | MATLAB實現WOA-CNN-GRU鯨魚算法優化卷積門控循環單元時間序列預測預測效果基本介紹模型描述程序設計參考資料 預測效果 基本介紹 時序預測 | MATLAB實現WOA-CNN-GRU鯨魚算法優化卷積…

PrefetchParameters

Windows XP重新設置預讀對象是允許的。具體方法是&#xff1a;打開注冊表編輯器&#xff0c;依次展開 HKEY_LOCAL_MACHINE&#xff3c;SYSTEM&#xff3c;CurrentControlSet&#xff3c;Control&#xff3c;Session Manager&#xff3c;Memory Management&#xff3c;PrefetchP…

基于LVQ神經網絡的人臉朝向識別

1案例背景 1.1人臉識別概述 人臉識別作為一個復雜的模式識別問題,近年來受到了廣泛的關注,識別領域的各種方法在這個問題上各顯所長,而且發展出了許多新方法,大大豐富和拓寬了模式識別的方向。人臉識別、檢測,跟蹤、特征定位等技術近年來一直是研究的熱點。人臉識別是人臉應用…

【制作npm包1】申請npm賬號、認識個人包和組織包

概述 在開發當中經常有一種現象&#xff0c;重復代碼寫了N多遍&#xff0c;再次寫同樣的邏輯就再次翻查以前的代碼邏輯。效率低下且容易出錯&#xff0c;封裝一個npm包的價值也不僅僅是給別人用&#xff0c;封裝一套屬于自己或者本部門的npm包也是相當有必要。 也許經常看到一…

RabbitMQ的5種消息隊列

RabbitMQ的5種消息隊列 1、七種模式介紹與應用場景 1.1 簡單模式(Hello World) 一個生產者對應一個消費者&#xff0c;RabbitMQ 相當于一個消息代理&#xff0c;負責將 A 的消息轉發給 B。 應用場景&#xff1a;將發送的電子郵件放到消息隊列&#xff0c;然后郵件服務在隊列…

【JS學習】Object.assign 用法介紹

Object.assign 是ES6中的一個方法。該方法能夠實現對象的淺復制以及對象合并。Object.assign 并不會修改目標對象本身&#xff0c;而是返回一個新的對象&#xff0c;其中包含了所有源對象的屬性。 例1 2個對象合并 const target { a: 1, b: 2 }; const source { b: 3, c: 4…

【git】初次使用git上傳代碼到github遠程倉庫

目錄 0.前言1.新建代碼庫2.添加SSH公鑰2.1 前置準備2.2 Git 基本信息設置2.3 添加SSH Key 3.本地倉庫上傳到github3.1 建立本地倉庫并初始化3.2 初始化倉庫3.3 建立本地與github上新建項目鏈接3.4 同步github新建項目到本地3.5 添加本地文件到緩存區3.6 為上傳文件添加注釋3.7 …

注冊中心Eureka和Nacos,以及負載均衡Ribbon

1.初識微服務 1.1.什么是微服務 微服務&#xff0c;就是把服務拆分成為若干個服務&#xff0c;降低服務之間的耦合度&#xff0c;提供服務的獨立性和靈活性。做到高內聚&#xff0c;低耦合。 1.2.單體架構和微服務架構的區別&#xff1a; 單體架構&#xff1a;簡單方便&#…

TS基本語法

一、安裝 npm install -g typescript 或者 cnpm install -g typescript 或者 yarnlobal add typescript二、運行 tsc xxxx.ts注意&#xff1a;如果電腦上面沒有安裝過cnpm&#xff0c;請先安裝cnpm npm install -g cnpm --registryhttps://registry.npm.taobao.org注意&…