Interesting data structures: the BK-tree
signal-to-noise.xyz
signal-to-noise.xyz
The core is a single, header-only BK-tree implementation here: https://github.com/fake-name/IntraArchiveDeduplicator/blob/m....
There are also relatively comprehensive unit-tests for the whole thing: https://github.com/fake-name/IntraArchiveDeduplicator/tree/m...
I use it for image deduplication across a ~28M image dataset. It works quite well, though it does take a lot of ram to hold the entire dataset in memory (~18 GB).
Or even better: a bloom filter to find likely duplicates?
I'm familiar with location-sensitive hashing[1], which acts like a dimensionality reducer but, instead of receiving as input the image itself receives a feature vector extracted from it (or something analogous that allows for similarity assessment).
[1] https://en.wikipedia.org/wiki/Locality-sensitive_hashing
A bloom filter is useless, as it doesn't let you do searches within an edit distance. Basically, I use a BK-tree of perceptual hashes (https://en.wikipedia.org/wiki/Perceptual_hashing). Then, I can find similar images by searching within a certain edit-distance.
Basically, the end result is a system that functions very similarly to how google's reverse image search works.
It uses locality sensitive hashing to hash vectors into buckets. These buckets are a subset of the total set of items. It worked with similar images of a small size when I used it, but I didn't have many images.
In my case, the vectors were just the rgb values of the down-sampled image.
Metric-based data structures face the peculiar problem that the identity of each data point itself is not an actual "key", in the way that a data point in a hash-table or binary tree is a key. Rather, each data point in a metric tree is only "indexed" with relation to it's distance from all other keys. This makes it hard to get easily measured performance guarantees.
Interesting tid-bit, one Mr. Sergey Brin published this in 1995
"Near Neighbor Search in Large Metric Spaces"
http://www.vldb.org/conf/1995/P574.PDF
So I'm curious, because I had been planning on using a VP tree for something I'm mulling over. I could see stormy waters though for large dimensions.
Seriously interested to hear any feedback from people who have tried it. Any recommendations for what to do instead?
I feel like the poster-child for the frequency illusion. There was an article on 538 a few weeks ago that caught my interest which used cosine similarity (a non-metric distance function). I dove in, and started wondering if there were any ways to find nearest neighbors using cosine similarity efficiently. A week later, Facebook's Faiss implements something of a general purpose toolkit for indexing metric and not metric spaces to minimize storage. And now this. It's like the world is trying to tell me something!
[0] http://scikit-learn.org/stable/modules/neighbors.html#k-d-tr...
EDIT: Deleted calculation about approximating arccos(z) <= arccos(x) + arccos(y) by cos(arccos(z)) <= cos(arccos(x) + arccos(y)) <= xy - (1-x^2)(1-y^2), completely disregarding that cos is a decreasing function in the relevant interval.
(AFAICT: Most of these trees have a "typical" case search time of some root of N based on dimensionality. The easiest way to visualize this is to consider a walk from the perimeter to a cell in Voroni space, and how many cells that will search.)
* https://pypi.python.org/pypi/pybktree/1.0 * http://tech.jetsetter.com/2017/03/21/duplicate-image-detecti...
IMO there is no data structure better suited for a search tree than the doubly-chained character trie [0], as it has the following features:
- small in memory (every word is stored once at the most, but more often less than once)
- traversing and doing exact matching allow you to prune half of the tree at every step
- requires you to calculate the distance only at querying time, not when constructing the tree
- apart from exact and fuzzy matches also support prefix matches (traverse up to the path of the prefix, return all children that are EndOfWords)
- can be represented on disk in a way that makes reading insignificantly slower than reading from memory
- if nodes are lexically sorted when tree is constructed, you have also pretty much solved range queries
[0] https://github.com/kreeben/resin/blob/master/src/Resin/IO/Lc...
The trie is to be the perfect tool for when you find yourself combatting big data. What you find out eventually about all of the cloud offerings from all of the big players that claim they will solve both storing and map/reducing over your data is that you can do the same thing on your laptop, for cheap money, as long as the data is represented in a compressed form that still allow for querying. The trie is a zip file and a search engine in one.
Edit: formatting and clarification
Yes, but you do know that the distance from London to Rome is less than 12,000 km, because of the triangle inequality axiom. So if that's too far, that search path is discarded.
Then we just start the process over again, by comparing each subtree back to the original location.
I'm struggling with finding a use case for that data structure through. Why would you construct a BK-tree that would only become powerful when it contains millions of words, which would then create a nuisance when representing that amount of data in memory, making it not so fast anymore, when you could represent the same data in a compressed form and with the same (as well as an extended set of) querying capabilities?
Perhaps BK-trees are for big machines with powerful CPUs? I'm sure there is a setup that would make that tree in fact better than any other tree.
Is there some rationale? And can it be extended to non-integer metrics?
A BK-tree is... specifically adapted to discrete metric spaces.
There are others that have a similar principal for real valued metrics.• Ball Tree (also known as VP-Tree) (implemented in sklearn)
• GH-Tree (rough description in this large PDF https://github.com/searchivarius/nmslib/raw/master/docs/manu... )
• Multi-Vantage Point Tree
As for the rationale, I think grouping them together is an efficient way to exploit the triangle inequality for each subtree.
But it doesn't work as well as you expect. A metric tree requires a true metric to be used as the distance function, which means the distance function must satisfy both symmetry and triangle inequality. Levenshtein distance satisfies this - but unfortunately this usually isn't enough for a robust spell-checker that just "does the right thing". For that, you usually need something like a weighted levenshtein distance (e.g., an incorrect first character should weigh more than an incorrect Nth character, or an incorrect consonant should weigh more than an incorrect vowel). But it is much harder to guarantee that such a distance function is a true metric.
It's possible that this is true for how most people type, but not for me.
Making things symmetrical might not make as much sense though, omitting a letter might be far more likely than adding an additional letter, for instance. Assuming it satisfies all other axioms you should be able to turn this into a true metric, by just measuring the distance both ways and taking the average.
Then again it looks like the BK-tree might not need the symmetry axiom, at least not in an obvious way.
Also, is there a link between the sematic and conceptual distance between two terms, does anyone know?
It would surprise me if there was such a correlation, because the concepts of "near" are different in the semantic and conceptual world. Then again, it would be facinating if there was.
FWIW, Deque is actually more like a vector.
Wayback machine to the rescue!
https://web.archive.org/web/20160629190654/http://stevehanov...
Businesses are getting crushed under the weight of their data. They "solve" it by stashing it onto Hadoop. Unfortunately, no one then knows how to map/reduce over that data. So they're none the wiser even though they kept the data that could have made their analysts smarter than their competitor's. This of course totally awsome if you're a Hadoop consultant.
Well, that's at least why I dwell on data structures.
Edit: spelin
None of them look obviously inappropriate but maybe the algorithm sees something I can't. There is a high-ish submission frequency (2-3 per day).
Which might be related?
I chose it because .io was way too expensive for my student budget and xyz looked cool.