% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/spatial.R
\name{spatial_knn}
\alias{spatial_knn}
\title{k nearest neighbours of a streamed layer, with distances}
\usage{
spatial_knn(
  x,
  y,
  k = 1L,
  geom = "geometry",
  coords = NULL,
  crs = NA,
  y_id = NULL,
  id_col = "neighbor",
  dist_col = "distance",
  rank_col = "rank",
  out_geom = NULL,
  flush_rows = NULL
)
}
\arguments{
\item{x}{A \code{vectra_node} (from \code{\link[=tbl]{tbl()}}, \code{\link[=tbl_tiff]{tbl_tiff()}}, any verb chain, ...).
It is consumed by the stream.}

\item{y}{An \code{sf} or \code{sfc} object: the resident candidate-neighbour layer.}

\item{k}{Number of nearest neighbours to return per left feature (capped at
the number of \code{y} features). Default \code{1}.}

\item{geom}{Name of the input geometry column holding hex-WKB or WKT strings.
Default \code{"geometry"}. Ignored when \code{coords} is given.}

\item{coords}{Optional length-2 character vector naming the x and y
coordinate columns to assemble point geometry from (e.g. \code{c("x", "y")}),
for inputs such as \code{\link[=tiff_extract_points]{tiff_extract_points()}} output. The coordinate columns
are retained.}

\item{crs}{Coordinate reference system of the input geometry, in any form
\code{\link[sf:st_crs]{sf::st_crs()}} accepts (EPSG integer, WKT, proj string). Defaults to the
CRS the upstream node carries, or unknown.}

\item{y_id}{Optional name of a column in \code{y} whose value identifies each
neighbour in the output. Default \code{NULL} uses \code{y}'s 1-based row index.}

\item{id_col, dist_col, rank_col}{Names of the output columns holding the
neighbour identifier, the distance, and the 1-based rank (1 = nearest).
Defaults \code{"neighbor"}, \code{"distance"}, \code{"rank"}.}

\item{out_geom}{Name of the output geometry column. Defaults to \code{geom}
(or \code{"geometry"} when \code{coords} is used).}

\item{flush_rows}{Transformed rows buffered before a spill flush. Larger
values mean fewer, bigger temporary files. Defaults to
\code{getOption("vectra.spatial_flush", 5e5)}.}
}
\value{
A \code{vectra_node} of one row per (left, neighbour) pair -- \code{x}'s columns
(geometry included) plus the rank, neighbour identifier, and distance --
backed by temporary \code{.vtr} spills (removed when the node is garbage-
collected) and carrying the input CRS.
}
\description{
Streams a large left side \code{x} through the engine and, for each feature, finds
the \code{k} nearest features of a small resident layer \code{y}, returning one row per
(left, neighbour) pair with the neighbour's rank, identifier, and distance.
Where \code{\link[=spatial_join]{spatial_join()}} with \link[sf:st_nearest_feature]{sf::st_nearest_feature} attaches only the single
nearest match, this returns the top \code{k} and the distances themselves -- the
nearest-\code{k} query and the building block of a distance matrix. The billion-row
left stream never materializes; \code{y} (the candidate neighbours) stays resident.
}
\details{
Distances are \pkg{sf}'s \code{\link[sf:st_distance]{sf::st_distance()}}: planar (CRS units) on projected
or unprojected planar data, great-circle (metres) on geographic coordinates
with spherical geometry on (\code{sf::sf_use_s2()}). Each batch forms its
left-by-\code{y} distance matrix, so \code{y} should be the small side; when \code{y} carries
no CRS it inherits the stream's. The left geometry rides through unchanged
(replicated once per neighbour). The \pkg{sf} package is an optional
dependency (Suggests).
}
\examples{
\dontshow{if (requireNamespace("sf", quietly = TRUE)) withAutoprint(\{ # examplesIf}
nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
towns <- sf::st_centroid(sf::st_geometry(nc))[1:5]
towns <- sf::st_sf(town = nc$NAME[1:5], geometry = towns)

set.seed(1)
pts <- sf::st_coordinates(sf::st_sample(nc, 100))
f <- tempfile(fileext = ".vtr")
write_vtr(data.frame(id = seq_len(nrow(pts)), x = pts[, 1], y = pts[, 2]), f)

# The two nearest towns to each point, with distances.
tbl(f) |>
  spatial_knn(towns, k = 2, coords = c("x", "y"), crs = sf::st_crs(nc),
              y_id = "town") |>
  collect() |> head()
unlink(f)
\dontshow{\}) # examplesIf}
}
\seealso{
\code{\link[=spatial_join]{spatial_join()}} for a nearest-feature attribute join, \code{\link[=collect_sf]{collect_sf()}}
to materialize as \code{sf}.
}
