R 教學#

關於新增 lubridate 綁定的 R 教學#

在本教學中,我們將記錄如何依照指南的快速參考章節以及更詳細的首次 PR 的步驟章節中指定的步驟,貢獻 Arrow R 套件的綁定。當您發現此處缺少某些資訊時,請隨時查閱這些章節。

此綁定將新增至 R 套件中的 expression.R 檔案。但是,如果您要新增的綁定將位於其他位置,您也可以按照這些步驟操作。

本教學與首次 PR 的步驟不同,因為我們將處理一個特定的案例。本教學並非旨在作為逐步指南。

開始吧!

設定#

讓我們設定 Arrow 儲存庫。我們在此假設 Git 已經安裝。否則,請參閱設定章節。

一旦 Fork 了 Apache Arrow 儲存庫 (請參閱Fork 儲存庫),我們將複製它並將主要儲存庫的連結新增到我們的上游。

$ git clone https://github.com/<your username>/arrow.git
$ cd arrow
$ git remote add upstream https://github.com/apache/arrow

建置 R 套件#

建置 R 套件的步驟會因您使用的作業系統而異。因此,在本教學中,我們僅參考建置過程的說明。

另請參閱

關於建置過程的簡介,請參閱建置 Arrow 函式庫 🏋🏿‍♀️章節。

關於如何建置 R 套件的說明,請參閱 R 開發者文件

問題#

在本教學中,我們將處理一個問題,即實作一個簡單的 mday() 函數的綁定,該函數將與 lubridate 中現有的 R 函數相符。

注意

如果您沒有問題並且需要協助尋找問題,請參閱指南的尋找適合新手入門的問題 🔎部分。

一旦您選定了一個問題並分配給自己,就可以繼續下一步。

開始在新分支上工作#

在開始新增綁定之前,我們應該從更新後的主分支建立一個新分支。

$ git checkout main
$ git fetch upstream
$ git pull --ff-only upstream main
$ git checkout -b ARROW-14816

現在我們可以開始研究 R 函數和我們想要公開或連接的 C++ Arrow 計算函數。

檢查 lubridate mday() 函數

瀏覽 lubridate 文件,我們可以看到 mday() 接受日期物件並傳回月份中的日期作為數值物件。

我們可以在 R 主控台中執行一些範例,以幫助我們更好地理解該函數

> library(lubridate)
> mday(as.Date("2000-12-31"))
[1] 31
> mday(ymd(080306))
[1] 6

檢查 Arrow C++ day() 函數

計算函數文件中,我們可以看到 day 是一個一元函數,這表示它接受單一資料輸入。資料輸入必須是 Temporal class,傳回值是 Integer/numeric 類型。

Temporal class 指定為:日期類型 (Date32, Date64)、時間類型 (Time32, Time64)、Timestamp、Duration、Interval。

我們可以從 R 主控台使用 call_function 呼叫 Arrow C++ 函數,以查看其運作方式

> call_function("day", Scalar$create(lubridate::ymd("2000-12-31")))
Scalar
31

我們可以看到 lubridate 和 Arrow 函數運作於並傳回等效的資料類型。lubridate 的 mday() 函數沒有額外的引數,並且 Arrow C++ 函數 day() 也沒有相關聯的選項類別。

查看 expressions.R 中的程式碼,我們可以看到 day 函數已經在 R 套件端指定/對應:apache/arrow

我們只需要將 mday() 新增到表達式列表中,將其連接到 C++ day 函數。

# second is defined in dplyr-functions.R
# wday is defined in dplyr-functions.R
"mday" = "day",
"yday" = "day_of_year",
"year" = "year",

新增測試#

現在我們需要新增一個測試,以檢查一切是否運作良好。如果還有其他選項或邊緣情況,我們將必須新增更多測試。查看類似函數 (例如 yday()day()) 的測試,我們可以看到新增兩個測試的好地方是在 test-dplyr-funcs-datetime.R

test_that("extract mday from timestamp", {
  compare_dplyr_binding(
    .input %>%
      mutate(x = mday(datetime)) %>%
      collect(),
    test_df
  )
})

而且

test_that("extract mday from date", {
  compare_dplyr_binding(
    .input %>%
      mutate(x = mday(date)) %>%
      collect(),
    test_df
  )
})

現在我們需要查看測試是否通過,或者我們是否需要進行更多研究和程式碼修正。

devtools::test(filter="datetime")

> devtools::test(filter="datetime") Loading arrow
See arrow_info() for available features Testing arrow
See arrow_info() for available features | F W S  OK | Context | 1     230 | dplyr-funcs-datetime [1.4s]
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Failure (test-dplyr-funcs-datetime.R:187:3): strftime
``%>%`(...)` did not throw the expected error.
Backtrace:
 1. testthat::expect_error(...) test-dplyr-funcs-datetime.R:187:2
 2. testthat:::expect_condition_matching(...)
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

══ Results ═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
Duration: 1.4 s

[ FAIL 1 | WARN 0 | SKIP 0 | PASS 230 ]

我們在 strftime 函數中遇到一個失敗,但是查看程式碼,我們發現它與我們的工作無關。我們可以繼續前進,並詢問其他人在執行測試時是否也遇到類似的失敗。可能我們只需要重新建置函式庫。

檢查風格#

我們也應該執行程式碼風格檢查器,以檢查程式碼的風格是否遵循 tidyverse 風格。為此,我們在 Shell 中執行以下命令

$ make style
R -s -e 'setwd(".."); if (requireNamespace("styler")) styler::style_file(setdiff(system("git diff --name-only | grep r/.*R$", intern = TRUE), file.path("r", source("r/.styler_excludes.R")$value)))'
Loading required namespace: styler
Styling  2  files:
 r/R/expression.R                             ✔
 r/tests/testthat/test-dplyr-funcs-datetime.R ℹ
────────────────────────────────────────────
Status   Count Legend
✔  1  File unchanged.
ℹ  1  File changed.
✖  0  Styling threw an error.
────────────────────────────────────────────
Please review the changes carefully!

建立 Pull Request#

首先,讓我們使用 Shell 中的 git status 檢閱我們的變更,以查看哪些檔案已變更,並僅提交我們正在處理的檔案。

$ git status
On branch ARROW-14816
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
   modified:   R/expression.R
   modified:   tests/testthat/test-dplyr-funcs-datetime.R

然後使用 git diff 查看檔案中的變更,以便發現我們可能犯的任何錯誤。

$ git diff
diff --git a/r/R/expression.R b/r/R/expression.R
index 37fc21c25..0e71803ec 100644
--- a/r/R/expression.R
+++ b/r/R/expression.R
@@ -70,6 +70,7 @@
   "quarter" = "quarter",
   # second is defined in dplyr-functions.R
   # wday is defined in dplyr-functions.R
+  "mday" = "day",
   "yday" = "day_of_year",
   "year" = "year",

diff --git a/r/tests/testthat/test-dplyr-funcs-datetime.R b/r/tests/testthat/test-dplyr-funcs-datetime.R
index 359a5403a..228eca56a 100644
--- a/r/tests/testthat/test-dplyr-funcs-datetime.R
+++ b/r/tests/testthat/test-dplyr-funcs-datetime.R
@@ -444,6 +444,15 @@ test_that("extract wday from timestamp", {
   )
 })

+test_that("extract mday from timestamp", {
+  compare_dplyr_binding(
+    .input %>%
+      mutate(x = mday(datetime)) %>%
+      collect(),
+    test_df
+  )
+})
+
 test_that("extract yday from timestamp", {
   compare_dplyr_binding(
     .input %>%
@@ -626,6 +635,15 @@ test_that("extract wday from date", {
   )
 })

+test_that("extract mday from date", {
+  compare_dplyr_binding(
+    .input %>%
+      mutate(x = mday(date)) %>%
+      collect(),
+    test_df
+  )
+})
+
 test_that("extract yday from date", {
   compare_dplyr_binding(
     .input %>%

一切看起來都沒問題。現在我們可以進行提交 (將我們的變更儲存到分支歷史記錄)

$ git commit -am "Adding a binding and a test for mday() lubridate"
[ARROW-14816 ed37d3a3b] Adding a binding and a test for mday() lubridate
 2 files changed, 19 insertions(+)

我們可以使用 git log 檢查提交歷史記錄

$ git log
commit ed37d3a3b3eef76b696532f10562fea85f809fab (HEAD -> ARROW-14816)
Author: Alenka Frim <frim.alenka@gmail.com>
Date:   Fri Jan 21 09:15:31 2022 +0100

    Adding a binding and a test for mday() lubridate

commit c5358787ee8f7b80f067292f49e5f032854041b9 (upstream/main, upstream/HEAD, main, ARROW-15346, ARROW-10643)
Author: Krisztián Szűcs <szucs.krisztian@gmail.com>
Date:   Thu Jan 20 09:45:59 2022 +0900

    ARROW-15372: [C++][Gandiva] Gandiva now depends on boost/crc.hpp which is missing from the trimmed boost archive

    See build error https://github.com/ursacomputing/crossbow/runs/4871392838?check_suite_focus=true#step:5:11762

    Closes #12190 from kszucs/ARROW-15372

    Authored-by: Krisztián Szűcs <szucs.krisztian@gmail.com>
    Signed-off-by: Sutou Kouhei <kou@clear-code.com>

如果我們在不久前啟動了分支,我們可能需要 Rebase 到上游主分支,以確保沒有合併衝突

$ git pull upstream main --rebase

現在我們可以將我們的工作推送到 GitHub 上名為 origin 的 Fork Arrow 儲存庫。

$ git push origin ARROW-14816
Enumerating objects: 233, done.
Counting objects: 100% (233/233), done.
Delta compression using up to 8 threads
Compressing objects: 100% (130/130), done.
Writing objects: 100% (151/151), 35.78 KiB | 8.95 MiB/s, done.
Total 151 (delta 129), reused 33 (delta 20), pack-reused 0
remote: Resolving deltas: 100% (129/129), completed with 80 local objects.
remote:
remote: Create a pull request for 'ARROW-14816' on GitHub by visiting:
remote:      https://github.com/AlenkaF/arrow/pull/new/ARROW-14816
remote:
To https://github.com/AlenkaF/arrow.git
 * [new branch]          ARROW-14816 -> ARROW-14816

現在我們必須前往 GitHub 上的 Arrow 儲存庫 以建立 Pull Request。在 GitHub Arrow 頁面 (主要或 Fork) 上,我們將看到一個黃色通知欄,其中註明我們最近推送了到 ARROW-14816 分支的內容。太棒了,現在我們可以點擊 Compare & pull request 來建立 Pull Request。

GitHub page of the Apache Arrow repository showing a notice bar indicating change has been made in our branch and a Pull Request can be created.

Apache Arrow 儲存庫上的通知欄。#

首先,我們需要將標題更改為 ARROW-14816: [R] 實作 lubridate::mday() 的綁定,以便與問題相符。請注意,已新增標點符號!

額外說明:在本教學建立時,我們一直使用 Jira 問題追蹤器。由於我們目前使用 GitHub Issues,因此標題將以 GH-14816: [R] 實作 lubridate::mday() 的綁定 為前綴.

我們也將新增描述,以向其他人清楚說明我們嘗試做的事情。

GitHub page of the Pull Request showing the editor for the title and a description.

編輯我們的 Pull Request 的標題和描述。#

一旦我們點擊 Create pull request,我們的程式碼就可以在 Apache Arrow 儲存庫中作為 Pull Request 進行審閱。

GitHub page of the Pull Request showing the title and a description.

這就是我們的 Pull Request!#

Pull Request 已連接到問題,並且 CI 正在執行。經過一段時間並收到審閱後,我們可以更正程式碼、評論、解決對話等等。

另請參閱

有關 Pull Request 工作流程的更多資訊,請參閱 Pull Request 的生命週期

我們建立的 Pull Request 可以在這裡查看。