Zum Inhalt springen

R-Client

Installation Um den DuckDB-R-Client zu verwenden, besuchen Sie die R-Installationsseite.

Die aktuelle stabile Version des DuckDB-R-Clients ist 1.5.5

Installation

duckdb: R-Client

Der DuckDB-R-Client kann mit dem folgenden Befehl installiert werden:

install.packages("duckdb")

Details finden Sie auf der Installationsseite und bei CRAN.

duckplyr: dplyr-Client

DuckDB bietet eine dplyr-kompatible API über das Paket duckplyr. Es kann mit install.packages("duckplyr") installiert werden. Details finden Sie in der duckplyr-Dokumentation.

Referenzhandbuch

Das Referenzhandbuch für den DuckDB-R-Client ist unter r.duckdb.org verfügbar.

Grundlegende Client-Nutzung

Der Standard-DuckDB-R-Client implementiert die DBI-Schnittstelle für R. Falls Sie mit DBI noch nicht vertraut sind, finden Sie auf der Seite Using DBI eine Einführung.

Start und Beenden

Um DuckDB zu verwenden, müssen Sie zuerst ein Verbindungsobjekt erzeugen, das die Datenbank repräsentiert. Das Verbindungsobjekt nimmt als Parameter die Datenbankdatei entgegen, aus der gelesen und in die geschrieben werden soll. Wenn die Datenbankdatei nicht existiert, wird sie erstellt (die Dateierweiterung kann .db, .duckdb oder etwas anderes sein). Der Sonderwert :memory: (der Standard) kann verwendet werden, um eine In-Memory-Datenbank zu erzeugen. Beachten Sie, dass bei einer In-Memory-Datenbank keine Daten auf die Festplatte geschrieben werden (d. h. alle Daten gehen verloren, wenn Sie den R-Prozess beenden). Wenn Sie sich mit einer bestehenden Datenbank im Nur-Lese-Modus verbinden möchten, setzen Sie das Flag read_only auf TRUE. Der Nur-Lese-Modus ist erforderlich, wenn mehrere R-Prozesse gleichzeitig auf dieselbe Datenbankdatei zugreifen möchten.

library("duckdb")
# to start an in-memory database
con <- dbConnect(duckdb())
# or
con <- dbConnect(duckdb(), dbdir = ":memory:")
# to use a database file (not shared between processes)
con <- dbConnect(duckdb(), dbdir = "my-db.duckdb", read_only = FALSE)
# to use a database file (shared between processes)
con <- dbConnect(duckdb(), dbdir = "my-db.duckdb", read_only = TRUE)

Verbindungen werden implizit geschlossen, wenn sie außer Scope gehen, oder explizit mit dbDisconnect(). Um die mit der Verbindung verknüpfte Datenbankinstanz herunterzufahren, verwenden Sie duckdb_shutdown() auf dem von duckdb() zurückgegebenen Treiberobjekt.

Abfragen

DuckDB unterstützt die Standard-DBI-Methoden zum Senden von Abfragen und Abrufen von Ergebnissets. dbExecute() ist für Abfragen gedacht, bei denen keine Ergebnisse erwartet werden, etwa CREATE TABLE oder UPDATE usw., und dbGetQuery() ist für Abfragen gedacht, die Ergebnisse liefern (z. B. SELECT). Im Folgenden ein Beispiel.

# create a table
dbExecute(con, "CREATE TABLE items (item VARCHAR, value DECIMAL(10, 2), count INTEGER)")
# insert two items into the table
dbExecute(con, "INSERT INTO items VALUES ('jeans', 20.0, 1), ('hammer', 42.2, 2)")
# retrieve the items again
res <- dbGetQuery(con, "SELECT * FROM items")
print(res)
# item value count
# 1 jeans 20.0 1
# 2 hammer 42.2 2

DuckDB unterstützt im R-Client auch Prepared Statements mit den Methoden dbExecute und dbGetQuery. Hier ein Beispiel:

# prepared statement parameters are given as a list
dbExecute(con, "INSERT INTO items VALUES (?, ?, ?)", list('laptop', 2000, 1))
# if you want to reuse a prepared statement multiple times, use dbSendStatement() and dbBind()
stmt <- dbSendStatement(con, "INSERT INTO items VALUES (?, ?, ?)")
dbBind(stmt, list('iphone', 300, 2))
dbBind(stmt, list('android', 3.5, 1))
dbClearResult(stmt)
# query the database using a prepared statement
res <- dbGetQuery(con, "SELECT item FROM items WHERE value> ?", list(400))
print(res)
# item
# 1 laptop

Warning Verwenden Sie Prepared Statements nicht, um große Datenmengen in DuckDB einzufügen. Siehe unten für bessere Optionen.

Effizienter Transfer

Um einen R-Data-Frame in DuckDB zu schreiben, verwenden Sie die Standard-DBI-Funktion dbWriteTable(). Damit wird eine Tabelle in DuckDB erzeugt und mit dem Inhalt des Data Frames befüllt. Zum Beispiel:

dbWriteTable(con, "iris_table", iris)
res <- dbGetQuery(con, "SELECT * FROM iris_table LIMIT 1")
print(res)
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1 5.1 3.5 1.4 0.2 setosa

Es ist auch möglich, einen R-Data-Frame als virtuelle Tabelle zu „registrieren“, vergleichbar mit einer SQL-VIEW. Dabei werden Daten noch nicht tatsächlich in DuckDB übertragen. Im Folgenden ein Beispiel:

duckdb_register(con, "iris_view", iris)
res <- dbGetQuery(con, "SELECT * FROM iris_view LIMIT 1")
print(res)
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1 5.1 3.5 1.4 0.2 setosa

DuckDB behält nach der Registrierung eine Referenz auf das R-Data-Frame. Das verhindert, dass das Data Frame vom Garbage Collector eingesammelt wird. Die Referenz wird gelöscht, wenn die Verbindung geschlossen wird, kann aber auch manuell mit der Methode duckdb_unregister() gelöscht werden.

Weitere Optionen für den effizienten Datenimport finden Sie in der Dokumentation zum Datenimport.

dbplyr

DuckDB funktioniert auch gut mit den Paketen dbplyr / dplyr zur programmatischen Abfragekonstruktion aus R. Hier ein Beispiel:

library("duckdb")
library("dplyr")
con <- dbConnect(duckdb())
duckdb_register(con, "flights", nycflights13::flights)
tbl(con, "flights") |>
group_by(dest) |>
summarise(delay = mean(dep_time, na.rm = TRUE)) |>
collect()

Bei Verwendung von dbplyr können CSV- und Parquet-Dateien mit der Funktion dplyr::tbl gelesen werden.

# Establish a CSV for the sake of this example
write.csv(mtcars, "mtcars.csv")
# Summarize the dataset in DuckDB to avoid reading the entire CSV into R's memory
tbl(con, "mtcars.csv") |>
group_by(cyl) |>
summarise(across(disp:wt, .fns = mean)) |>
collect()
# Establish a set of Parquet files
dbExecute(con, "COPY flights TO 'dataset' (FORMAT parquet, PARTITION_BY (year, month))")
# Summarize the dataset in DuckDB to avoid reading 12 Parquet files into R's memory
tbl(con, "read_parquet('dataset/**/*.parquet', hive_partitioning = true)") |>
filter(month == "3") |>
summarise(delay = mean(dep_time, na.rm = TRUE)) |>
collect()

Speicherlimit

Sie können die Konfigurationsoption memory_limit verwenden, um den Speicherverbrauch von DuckDB zu begrenzen, z. B.:

SET memory_limit = '2GB';

Beachten Sie, dass dieses Limit nur auf den von DuckDB verwendeten Speicher angewendet wird und den Speicherverbrauch anderer R-Bibliotheken nicht beeinflusst. Daher kann der gesamte vom R-Prozess verwendete Speicher höher sein als das konfigurierte memory_limit.

Fehlerbehebung

Warnung bei der Installation unter macOS

Unter macOS kann die Installation von DuckDB zu einer Warnung unable to load shared object '.../R_X11.so' führen:

Terminal window
Warning message:
In doTryCatch(return(expr), name, parentenv, handler) :
unable to load shared object '/Library/Frameworks/R.framework/Resources/modules//R_X11.so':
dlopen(/Library/Frameworks/R.framework/Resources/modules//R_X11.so, 0x0006): Library not loaded: /opt/X11/lib/libSM.6.dylib
Referenced from: <31EADEB5-0A17-3546-9944-9B3747071FE8> /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/modules/R_X11.so
Reason: tried: '/opt/X11/lib/libSM.6.dylib' (no such file) ...
> ')

Beachten Sie, dass es sich nur um eine Warnung handelt, die einfachste Lösung ist also, sie zu ignorieren. Alternativ können Sie DuckDB aus dem R-universe installieren:

install.packages("duckdb", repos = c("https://duckdb.r-universe.dev", "https://cloud.r-project.org"))

Sie können auch die optionale Abhängigkeit xquartz über Homebrew installieren.