Kueri jarak tempuh cepat di postgres

15

Saya memiliki basis data besar (16M baris) yang berisi hash perceptual gambar.

Saya ingin dapat mencari baris dengan jarak tempuh dalam jangka waktu yang masuk akal.

Saat ini, sejauh yang saya mengerti benar masalah ini, saya pikir pilihan terbaik di sini adalah implementasi SP-GiST kustom yang mengimplementasikan BK-Tree , tapi itu sepertinya banyak pekerjaan, dan saya masih bingung pada praktis rincian penerapan indeks kustom dengan benar. Menghitung jarak Hamming cukup penurut, dan saya lakukan tahu C, meskipun.

Pada dasarnya, apa pendekatan yang tepat di sini? Saya harus dapat meminta kecocokan dalam jarak edit tertentu dari hash. Seperti yang saya pahami, jarak Levenshtein dengan string dengan panjang yang sama secara fungsional adalah jarak hamming, jadi setidaknya ada beberapa dukungan yang ada untuk apa yang saya inginkan, meskipun tidak ada cara yang jelas untuk membuat indeks dari itu (ingat, nilai yang saya minta untuk perubahan. Saya tidak dapat melakukan pra-hitung jarak dari nilai tetap, karena itu hanya akan berguna untuk nilai yang satu itu).

Hash saat ini disimpan sebagai string 64-char yang berisi pengkodean ASCII biner dari hash (misalnya "10010101 ..."), tetapi saya dapat mengonversinya menjadi int64 dengan cukup mudah. Masalah sebenarnya adalah saya harus bisa melakukan query relatif cepat.

Sepertinya itu mungkin untuk mencapai sesuatu di sepanjang garis yang saya inginkan dengan pg_trgm, tapi saya agak tidak jelas tentang bagaimana mekanisme pencocokan trigram bekerja (khususnya, apa kesamaan metrik yang dikembalikan sebenarnya mewakili? Tampaknya jenis seperti edit-jarak).

Memasukkan kinerja tidak penting (sangat mahal secara komputasi untuk menghitung hash untuk setiap baris), jadi saya terutama peduli tentang pencarian.

Nama palsu
sumber
Ekstensi smlar mungkin memiliki apa yang Anda butuhkan: pgcon.org/2012/schedule/attachments/252_smlar-2012.pdf atau pg_similarity: pgcon.org/2009/schedule/attachments/108_pg_similarity.pdf
Neil McGuigan
@NeilMcGuigan - Menarik! Presentasi pertama sebenarnya ada dari orang-orang yang memelihara sistem SP-GiST dan GIST di postgres.
Palsu Nama
Tautan pertama adalah untuk sesuatu yang secara fundamental berbeda. mereka mencari persimpangan, sedangkan saya mencari jarak hamming. Saya bisa menyatukan phash menjadi satu set, tetapi akan sangat berantakan, dan membutuhkan banyak kode dukungan di tempat lain.
Nama Palsu
FWIW, Pada titik ini, saya kurang lebih telah menyimpulkan bahwa saya perlu menerapkan sistem pengindeksan saya sendiri. Saya sedang melihat indeks SP-GiST khusus saat ini, tetapi saya tidak tahu apa yang saya lakukan.
Nama Palsu
1
@FakeName: Ketika Anda mengatakan jarak hamming, saya berasumsi maksud Anda jarak hamming dari string nilai hash, bukan gambar? Dengan kata lain, Anda ingin bertanya: Temukan semua nilai hash yang merupakan substitusi X bit dari parameter input
Thomas Kejser

Jawaban:

11

Yah, saya menghabiskan waktu melihat penulisan ekstensi postgres C kustom, dan akhirnya hanya membungkus pembungkus basis data Cython yang mempertahankan struktur pohon-BK dalam memori.

Pada dasarnya, ia memelihara salinan dalam memori dari nilai-nilai phash dari database, dan semua pembaruan ke database diputar ulang ke pohon-BK.

Semuanya ada di github di sini . Ini juga memiliki BANYAK unit-tes.

Meminta set data 10 juta nilai hash untuk item dengan jarak 4 hasil menyentuh ~ 0,25% -0,5% dari nilai di pohon, dan membutuhkan ~ 100 ms.

Nama palsu
sumber
BK-Tree dalam memori dengan 16 juta baris dalam memori? Saya melihat sesuatu yang serupa namun dengan 1000 gambar dan 2000 deskriptor pada setiap gambar ukuran memori saya sangat besar.
Stewart
@ Mulai - Banyak dari ini tergantung pada ukuran hash Anda. Dalam kasus saya, output nilai hash adalah bitfield 64-bit tunggal yang saya simpan sebagai int64. Anda tampaknya memiliki tipe data phash yang jauh lebih besar. Saya juga tidak yakin bagaimana pencarian akan bekerja pada tipe data yang berbeda seperti itu. Apakah mereka masih ruang metrik? Bagaimana Anda menghitung jarak?
Nama Palsu
Saya menggunakan deskriptor 32-bit dengan FLANN marcher yang disediakan dengan OpenGL Untuk menghitung jarak, saya menggunakan hamming dengan ambang batas berdasarkan rasio Lowe. Pada titik ini saya tidak yakin apakah yang terbaik untuk mencoba dan bertahan dalam memori FLANN yang menyediakan struktur KD-tree atau untuk beralih ke solusi yang lebih mirip dengan milik Anda. Mengapa Anda akhirnya menggulung sendiri dan tidak pergi untuk sesuatu seperti libflann?
Stewart
@Mulailah - Saya tidak menggulung sendiri. Saya menggunakan hashing berbasis DFT yang sangat membosankan .
Nama Palsu
7

JAWABAN MOAR!

Oke, saya akhirnya meluangkan waktu untuk menulis ekstensi pengindeksan PostgreSQL khusus. Saya menggunakan antarmuka SP-GiST .

Ini cukup menantang, terutama karena Posgres besar .

Bagaimanapun, seperti biasa, ada di github di sini .

Dari segi kinerja, saat ini ~ 2-3 kali lebih lambat daripada implementasi murni-dalam-memori dalam jawaban saya yang lain untuk pertanyaan ini, tetapi jauh lebih nyaman untuk digunakan. Saya akan dengan senang hati memakan kinerja yang memukul (secara realistis, itu ~ 50 ms / query - 150 ms / query, yang masih cukup kecil).

Nama palsu
sumber
Kamu Menakjubkan! Bisakah Anda menambahkan README tentang cara memasang? Saya tidak pernah menginstal apa pun di Postgres: P
HypeWolf
1
@HypeWolf - Akar repo memiliki README . Apakah itu tidak mencakup apa yang Anda inginkan?
Nama Palsu
Kesalahan saya, saya tidak melihatnya, saya tidak yakin di mana saya mencari: /
HypeWolf
Sedang mencari README juga. Itu ada di folder root. Tautan akan menuju beberapa subfolder. Itu membingungkan.
luckydonald