Download the PHP package hexogen/kdtree without Composer
On this page you can find all versions of the php package hexogen/kdtree. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download hexogen/kdtree
More information about hexogen/kdtree
Files in hexogen/kdtree
Package kdtree
Short Description file system KDTree index
License MIT
Homepage https://github.com/hexogen/kdtree
Informations about the package kdtree
K-D Tree
PHP multidimensional K-D Tree implementation with k-nearest-neighbour search.
The tree is built in memory from a list of items (KDTree) and can be saved to a
compact binary file. The file-backed tree (FSKDTree) reads nodes lazily while
searching, so opening a large index costs almost nothing and searches touch only
the nodes they visit. This is much faster than unserializing a whole tree on every
request, and it is the recommended way to use the library for anything that does
not fit comfortably in memory or is rebuilt rarely and searched often.
Install
Via Composer
Requirements
- PHP 8.2 or newer; tested on PHP 8.2, 8.3, 8.4 and 8.5.
- A 64-bit PHP build for
FSKDTree/FSTreePersister: the binary format uses 64-bit integers, whichpack()/unpack()only support on 64-bit platforms. The in-memoryKDTreeworks on 32-bit builds too.
No extensions beyond the PHP core are needed.
Usage
All classes live in the Hexogen\KDTree namespace:
Tree creation
Every item has an integer id and a list of finite numeric coordinates; the number of coordinates must match the dimension count of the list. Adding an item whose id is already in the list replaces the earlier item, so ids should be unique. The tree is built once from the whole list: there is no incremental insert or delete, rebuild the tree when the data changes. Building is O(n log n) on average whatever the order of the input (the median is chosen with a random pivot).
Ids are plain ints because the binary file stores them as signed 64-bit
integers. Keep other data (names, payloads) in your own storage keyed by id.
Searching nearest items to the given point
Results are ordered nearest first by Euclidean distance. The second argument is
the number of items to return (default 1); asking for more items than the tree
holds returns all of them, asking for 0 returns an empty array, and searching an
empty tree returns an empty array. The point must have the same number of
dimensions as the tree.
Results carry the items only, not their distances. When you need the distance, compute it from the coordinates:
A NearestSearch instance can be reused for any number of searches on the same
tree.
Reproducible tree shape
The build picks pivots from a private random generator, so mt_srand() and
mt_rand() in your code are not affected. If you need the same tree layout on
every run (for example in tests or to get byte-identical persisted files), pass a
seeded Random\Randomizer:
The shape only affects build time and the on-disk layout; a search finds the same nearest items whatever the shape (items at exactly equal distances may come back in a different order).
Persist tree to a binary file
FSTreePersister writes to a temporary file in the same directory and renames it
over the target, so it is safe to rebuild a tree file while other processes are
reading it: readers never see a half-written file, and an FSKDTree that already
has the old file open keeps reading the old data until it is re-opened. On
failure the old file is left untouched and the temporary file is removed. Two
things to be aware of:
- On Windows the rename fails while another process has the target file open.
- The new file gets default permissions (your
umask), not the permissions of the file it replaces. Re-applychmod()after persisting if you rely on them.
File system version of the tree
FSKDTree implements the same KDTreeInterface as KDTree, so everything that
works on an in-memory tree works on a file-backed one. The factory decides which
class the items read from the file become; implement
Hexogen\KDTree\Interfaces\ItemFactoryInterface to get your own item objects
back from a search.
Opening a file reads only the header and validates that the file size matches the item count it declares. The file is opened read-only, so any number of processes can search the same file at the same time. The file handle stays open as long as the tree, or any node obtained from it, is referenced.
Nodes read from the file are cached, so a long-lived FSKDTree gradually loads
the whole file into memory. To bound memory, keep only the top levels cached:
With a cache depth of n at most 2^(n+1) - 1 nodes stay in memory; 0 keeps
only the root, null (the default) keeps everything ever read.
Boundaries
getMinBoundary() and getMaxBoundary() return the corners of the bounding box
that contains all items, as arrays indexed by dimension. On an empty tree they
are [INF, ...] and [-INF, ...] respectively, and getRoot() returns null.
Binary file format
FSTreePersister writes and FSKDTree reads format version 1. All integers and
floats are little-endian, floats are IEEE 754 doubles. The layout is described in
the FSKDTree docblock and summarised here (D is the number of dimensions,
N the number of items):
| Offset | Size | Content |
|---|---|---|
| 0 | 3 bytes | magic KDT |
| 3 | 1 byte | format version (1) |
| 4 | 4 bytes | D, unsigned 32-bit |
| 8 | 8 bytes | N, unsigned 64-bit |
| 16 | 8 × D bytes |
max boundary, D doubles |
| 16 + 8·D | 8 × D bytes |
min boundary, D doubles |
| 16 + 16·D | N nodes |
nodes, root first, pre-order (right subtree, then left) |
Each node is 24 + 8 × D bytes (FSKDTree::getNodeLength($dimensions)):
| Size | Content |
|---|---|
| 8 bytes | item id, signed 64-bit |
| 8 bytes | absolute file offset of the left child, 0 if none |
| 8 bytes | absolute file offset of the right child, 0 if none |
8 × D bytes |
coordinates, D doubles |
Files written by versions before 0.3.0 have no header and cannot be read anymore:
re-create them with FSTreePersister. The reader rejects files with a wrong
magic, an unsupported version, a dimension count of 0, or a size that does not
match N.
Errors
Invalid input and file problems are reported with exceptions, not PHP warnings.
Hexogen\KDTree\Exception\ValidationExceptionfor invalid arguments: an empty coordinate list, a coordinate that is not numeric or not finite (NAN,INF), an item or search point whose dimension count does not match the tree, anItemListwith0dimensions, or a negative result length.Hexogen\KDTree\Exception\FileException(aRuntimeException) fromFSKDTreeandFSTreePersisterwhen a file cannot be opened, written or renamed, is truncated, has an unsupported format, or when a node is read after the tree's file handle was closed.\OutOfRangeExceptionfromgetNthDimension()for a dimension index outside0 .. getDimensionsCount() - 1.\InvalidArgumentExceptionfrom theFSKDTreeconstructor for a negative cache depth.
Change log
Please see CHANGELOG for more information on what has changed recently.
Testing
The test suite runs on PHP 8.2–8.5 in CI with 100% code coverage; contributions are expected to keep it there.
Contributing
Please see CONDUCT for details.
Security
If you discover any security related issues, please email [email protected] instead of using the issue tracker.
Credits
- Volodymyr Basarab
- All Contributors
License
The MIT License (MIT). Please see License File for more information.