Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.
Membuat upserts yang efisien dengan langkah-langkah Gremlin mergeV () dan merGEE ()
Upsert (atau penyisipan kondisional) menggunakan kembali simpul atau tepi jika sudah ada, atau membuatnya jika tidak ada. Upserts yang efisien dapat membuat perbedaan yang signifikan dalam kinerja kueri Gremlin.
Upserts memungkinkan Anda menulis operasi penyisipan idempotent: tidak peduli berapa kali Anda menjalankan operasi seperti itu, hasil keseluruhannya sama. Ini berguna dalam skenario penulisan yang sangat bersamaan di mana modifikasi bersamaan pada bagian grafik yang sama dapat memaksa satu atau lebih transaksi untuk diputar kembali dengan aConcurrentModificationException, sehingga memerlukan percobaan ulang.
catatan
Lang mergeE() kah-langkah mergeV() dan memerlukan mesin Neptune versi 1.2.1.0 atau yang lebih baru, yang memperkenalkan dukungan TinkerPop 3.6. Jika cluster Anda menjalankan versi engine yang lebih lama, lihat sebagai Upserts yang efisien sebelum 3.6.x gantinya. Anda dapat memeriksa versi engine saat ini menggunakan titik akhir status instance.
Misalnya, kueri berikut meningkatkan simpul dengan menggunakan yang disediakan untuk terlebih dahulu Map mencoba menemukan simpul dengan of. T.id "v-1" Jika simpul itu ditemukan maka dikembalikan. Jika tidak ditemukan maka simpul dengan itu id dan properti dibuat melalui onCreate klausa.
g.mergeV([(id):'v-1']). option(onCreate, [(label): 'PERSON', 'email': 'person-1@example.org'])
Peningkatan batch untuk meningkatkan throughput
Untuk skenario penulisan throughput tinggi, Anda dapat membuat rantai mergeV() dan mergeE() melangkah bersama-sama untuk meningkatkan simpul dan tepi dalam batch. Batching mengurangi overhead transaksional dari peningkatan sejumlah besar simpul dan tepi. Anda kemudian dapat meningkatkan throughput lebih lanjut dengan meningkatkan permintaan batch secara paralel menggunakan beberapa klien.
Sebagai aturan praktis, kami merekomendasikan peningkatan sekitar 200 catatan per permintaan batch. Catatan adalah label atau properti simpul atau tepi tunggal. Sebuah simpul dengan label tunggal dan 4 properti, misalnya, membuat 5 catatan. Tepi dengan label dan properti tunggal membuat 2 catatan. Jika Anda ingin meningkatkan kumpulan simpul, masing-masing dengan label tunggal dan 4 properti, Anda harus mulai dengan ukuran batch 40, karena. 200 / (1 + 4)
= 40
Anda dapat bereksperimen dengan ukuran batch. 200 catatan per batch adalah titik awal yang baik, tetapi ukuran batch yang ideal mungkin lebih tinggi atau lebih rendah tergantung pada beban kerja Anda. Perhatikan, bagaimanapun, bahwa Neptunus dapat membatasi jumlah keseluruhan langkah Gremlin per permintaan. Batas ini tidak didokumentasikan, tetapi agar aman, cobalah untuk memastikan bahwa permintaan Anda berisi tidak lebih dari 1.500 langkah Gremlin. Neptunus dapat menolak permintaan batch besar dengan lebih dari 1.500 langkah.
Untuk meningkatkan throughput, Anda dapat meningkatkan batch secara paralel menggunakan beberapa klien (lihatMembuat Penulisan Gremlin Multithreaded yang Efisien). Jumlah klien harus sama dengan jumlah utas pekerja pada instance penulis Neptune Anda, yang biasanya 2 x jumlah vCPU di server. Misalnya, sebuah r5.8xlarge instance memiliki 32 vCPU dan 64 utas pekerja. Untuk skenario penulisan throughput tinggi menggunakan ar5.8xlarge, Anda akan menggunakan 64 klien yang menulis peningkatan batch ke Neptunus secara paralel.
Setiap klien harus mengirimkan permintaan batch dan menunggu permintaan selesai sebelum mengirimkan permintaan lain. Meskipun beberapa klien berjalan secara paralel, setiap klien individu mengirimkan permintaan secara serial. Ini memastikan bahwa server dilengkapi dengan aliran permintaan yang stabil yang menempati semua utas pekerja tanpa membanjiri antrian permintaan sisi server (lihatMengukur instans DB dalam sebuah klaster Neptune DB).
Cobalah untuk menghindari langkah-langkah yang menghasilkan banyak traverser
Ketika langkah Gremlin dieksekusi, dibutuhkan traverser yang masuk, dan memancarkan satu atau lebih penjelajah keluaran. Jumlah pelintas yang dipancarkan oleh satu langkah menentukan berapa kali langkah berikutnya dijalankan.
Biasanya, saat melakukan operasi batch, Anda ingin setiap operasi, seperti upsert vertex A, dijalankan sekali, sehingga urutan operasi terlihat seperti ini: upsert vertex A, lalu upsert vertex B, lalu upsert vertex C, dan seterusnya. Selama langkah membuat atau memodifikasi hanya satu elemen, ia memancarkan hanya satu traverser, dan langkah-langkah yang mewakili operasi berikutnya dijalankan hanya sekali. Jika, di sisi lain, operasi membuat atau memodifikasi lebih dari satu elemen, ia memancarkan beberapa traverser, yang pada gilirannya menyebabkan langkah-langkah berikutnya dijalankan beberapa kali, sekali per traverser yang dipancarkan. Hal ini dapat mengakibatkan database melakukan pekerjaan tambahan yang tidak perlu, dan dalam beberapa kasus dapat mengakibatkan penciptaan simpul tambahan, tepi atau nilai properti yang tidak diinginkan.
Contoh bagaimana hal-hal bisa salah adalah dengan kueri sepertig.V().addV(). Kueri sederhana ini menambahkan simpul untuk setiap simpul yang ditemukan dalam grafik, karena V() memancarkan traverser untuk setiap simpul dalam grafik dan masing-masing pelintas tersebut memicu panggilan ke. addV()
Lihat Mencampur bagian atas dan sisipan cara menangani operasi yang dapat memancarkan beberapa penjelajah.
Menaikkan simpul
mergeV()Langkah ini dirancang khusus untuk menaikkan simpul. Dibutuhkan sebagai argumen a Map yang mewakili elemen untuk dicocokkan dengan simpul yang ada dalam grafik, dan jika elemen tidak ditemukan, menggunakannya Map untuk membuat simpul baru. Langkah ini juga memungkinkan Anda untuk mengubah perilaku jika terjadi pembuatan atau kecocokan, di mana option() modulator dapat diterapkan dengan Merge.onCreate dan Merge.onMatch token untuk mengontrol perilaku masing-masing. Lihat Dokumentasi TinkerPop Refer
Anda dapat menggunakan ID simpul untuk menentukan apakah simpul tertentu ada. Ini adalah pendekatan yang disukai, karena Neptunus mengoptimalkan peningkatan untuk kasus penggunaan yang sangat bersamaan di sekitar ID. Sebagai contoh, kueri berikut membuat simpul dengan ID simpul tertentu jika belum ada, atau menggunakannya kembali jika ada:
g.mergeV([(T.id): 'v-1']). option(onCreate, [(T.label): 'PERSON', email: 'person-1@example.org', age: 21]). option(onMatch, [age: 22]). id()
Perhatikan bahwa kueri ini berakhir dengan id() langkah. Meskipun tidak sepenuhnya diperlukan untuk tujuan meningkatkan simpul, id() langkah ke akhir kueri upsert memastikan bahwa server tidak membuat serial semua properti simpul kembali ke klien, yang membantu mengurangi biaya penguncian kueri.
Atau, Anda dapat menggunakan properti vertex untuk mengidentifikasi simpul:
g.mergeV([email: 'person-1@example.org']). option(onCreate, [(T.label): 'PERSON', age: 21]). option(onMatch, [age: 22]). id()
Jika memungkinkan, gunakan ID Anda sendiri yang disediakan pengguna untuk membuat simpul, dan gunakan ID ini untuk menentukan apakah simpul ada selama operasi upsert. Ini memungkinkan Neptunus mengoptimalkan peningkatan. ID-based Upsert dapat secara signifikan lebih efisien daripada upsert berbasis properti ketika modifikasi bersamaan biasa terjadi.
Rantai-rantai puncak simpul
Anda dapat merangkai puncak simpul bersama-sama untuk menyisipkannya dalam satu batch:
g.V('v-1') .fold() .coalesce(unfold(), addV('Person').property(id, 'v-1') .property('email', 'person-1@example.org')) .V('v-2') .fold() .coalesce(unfold(), addV('Person').property(id, 'v-2') .property('email', 'person-2@example.org')) .V('v-3') .fold() .coalesce(unfold(), addV('Person').property(id, 'v-3') .property('email', 'person-3@example.org')) .id()
Atau, Anda juga dapat menggunakan mergeV() sintaks ini:
g.mergeV([(T.id): 'v-1', (T.label): 'PERSON', email: 'person-1@example.org']). mergeV([(T.id): 'v-2', (T.label): 'PERSON', email: 'person-2@example.org']). mergeV([(T.id): 'v-3', (T.label): 'PERSON', email: 'person-3@example.org'])
Namun, karena bentuk kueri ini menyertakan elemen dalam kriteria pencarian yang berlebihan untuk pencarian dasarid, itu tidak seefisien kueri sebelumnya.
Tepi yang naik
mergeE()Langkah ini dirancang khusus untuk memanjangkan tepi. Dibutuhkan Map sebagai argumen yang mewakili elemen untuk dicocokkan dengan tepi yang ada dalam grafik dan jika elemen tidak ditemukan, menggunakannya Map untuk membuat tepi baru. Langkah ini juga memungkinkan Anda untuk mengubah perilaku jika terjadi pembuatan atau kecocokan, di mana option() modulator dapat diterapkan dengan Merge.onCreate dan Merge.onMatch token untuk mengontrol perilaku masing-masing. Lihat Dokumentasi TinkerPop Refer
Anda dapat menggunakan ID tepi untuk memperbaiki tepi dengan cara yang sama seperti Anda menaikkan simpul menggunakan ID simpul khusus. Sekali lagi, ini adalah pendekatan yang disukai karena memungkinkan Neptunus untuk mengoptimalkan kueri. Misalnya, kueri berikut membuat tepi berdasarkan ID tepinya jika belum ada, atau menggunakannya kembali jika ada. Kueri juga menggunakan ID Direction.to simpul Direction.from dan jika perlu membuat tepi baru:
g.mergeE([(T.id): 'e-1']). option(onCreate, [(from): 'v-1', (to): 'v-2', weight: 1.0]). option(onMatch, [weight: 0.5]). id()
Perhatikan bahwa kueri ini berakhir dengan id() langkah. Meskipun tidak sepenuhnya diperlukan untuk tujuan meningkatkan tepi, menambahkan id() langkah ke akhir kueri upsert memastikan bahwa server tidak membuat serial semua properti tepi kembali ke klien, yang membantu mengurangi biaya penguncian kueri.
Banyak aplikasi menggunakan ID simpul khusus, tetapi meninggalkan Neptunus untuk menghasilkan ID tepi. Jika Anda tidak tahu ID tepi, tetapi Anda tahu ID simpul from danto, Anda dapat menggunakan kueri semacam ini untuk meningkatkan tepi:
g.mergeE([(from): 'v-1', (to): 'v-2', (T.label): 'KNOWS']). id()
Semua simpul yang direferensikan oleh mergeE() harus ada untuk langkah untuk membuat tepi.
Mengrantai bagian atas tepi
Seperti halnya upserts simpul, mudah untuk merangkai mergeE() langkah-langkah bersama untuk permintaan batch:
g.mergeE([(from): 'v-1', (to): 'v-2', (T.label): 'KNOWS']). mergeE([(from): 'v-2', (to): 'v-3', (T.label): 'KNOWS']). mergeE([(from): 'v-3', (to): 'v-4', (T.label): 'KNOWS']). id()
Menggabungkan puncak simpul dan tepi
Terkadang Anda mungkin ingin memperbaiki kedua simpul dan tepi yang menghubungkannya. Anda dapat mencampur contoh batch yang disajikan di sini. Contoh berikut menaikkan 3 simpul dan 2 tepi:
g.mergeV([(id):'v-1']). option(onCreate, [(label): 'PERSON', 'email': 'person-1@example.org']). mergeV([(id):'v-2']). option(onCreate, [(label): 'PERSON', 'email': 'person-2@example.org']). mergeV([(id):'v-3']). option(onCreate, [(label): 'PERSON', 'email': 'person-3@example.org']). mergeE([(from): 'v-1', (to): 'v-2', (T.label): 'KNOWS']). mergeE([(from): 'v-2', (to): 'v-3', (T.label): 'KNOWS']). id()
Mencampur bagian atas dan sisipan
Terkadang Anda mungkin ingin memperbaiki kedua simpul dan tepi yang menghubungkannya. Anda dapat mencampur contoh batch yang disajikan di sini. Contoh berikut menaikkan 3 simpul dan 2 tepi:
Upserts biasanya melanjutkan satu elemen pada satu waktu. Jika Anda tetap berpegang pada pola upsert yang disajikan di sini, setiap operasi upsert memancarkan traverser tunggal, yang menyebabkan operasi berikutnya dijalankan hanya sekali.
Namun, terkadang Anda mungkin ingin mencampur upserts dengan sisipan. Ini bisa terjadi, misalnya, jika Anda menggunakan tepi untuk mewakili contoh tindakan atau peristiwa. Permintaan mungkin menggunakan upserts untuk memastikan bahwa semua simpul yang diperlukan ada, dan kemudian menggunakan sisipan untuk menambahkan tepi. Dengan permintaan semacam ini, perhatikan jumlah potensial pelintas yang dipancarkan dari setiap operasi.
Pertimbangkan contoh berikut, yang menggabungkan upserts dan sisipan untuk menambahkan tepi yang mewakili peristiwa ke dalam grafik:
// Fully optimized, but inserts too many edges g.mergeV([(id):'v-1']). option(onCreate, [(label): 'PERSON', 'email': 'person-1@example.org']). mergeV([(id):'v-2']). option(onCreate, [(label): 'PERSON', 'email': 'person-2@example.org']). mergeV([(id):'v-3']). option(onCreate, [(label): 'PERSON', 'email': 'person-3@example.org']). mergeV([(T.id): 'c-1', (T.label): 'CITY', name: 'city-1']). V('p-1', 'p-2'). addE('FOLLOWED').to(V('p-1')). V('p-1', 'p-2', 'p-3'). addE('VISITED').to(V('c-1')). id()
Kueri harus memasukkan 5 tepi: 2 tepi YANG DIIKUTI dan 3 tepi YANG DIKUNJUNGI. Namun, kueri seperti tertulis menyisipkan 8 tepi: 2 DIIKUTI dan 6 DIKUNJUNGI. Alasan untuk ini adalah bahwa operasi yang memasukkan 2 tepi YANG DIIKUTI memancarkan 2 travers, menyebabkan operasi penyisipan berikutnya, yang menyisipkan 3 tepi, dieksekusi dua kali.
Perbaikannya adalah menambahkan fold() langkah setelah setiap operasi yang berpotensi memancarkan lebih dari satu traverser:
g.mergeV([(T.id): 'v-1', (T.label): 'PERSON', email: 'person-1@example.org']). mergeV([(T.id): 'v-2', (T.label): 'PERSON', email: 'person-2@example.org']). mergeV([(T.id): 'v-3', (T.label): 'PERSON', email: 'person-3@example.org']). mergeV([(T.id): 'c-1', (T.label): 'CITY', name: 'city-1']). V('p-1', 'p-2'). addE('FOLLOWED'). to(V('p-1')). fold(). V('p-1', 'p-2', 'p-3'). addE('VISITED'). to(V('c-1')). id()
Di sini kita telah memasukkan fold() langkah setelah operasi yang menyisipkan tepi YANG DIIKUTI. Ini menghasilkan traverser tunggal, yang kemudian menyebabkan operasi berikutnya dijalankan hanya sekali.
Kelemahan dari pendekatan ini adalah bahwa kueri sekarang tidak sepenuhnya dioptimalkan, karena tidak fold() dioptimalkan. Operasi sisipan yang berikut sekarang juga tidak fold() akan dioptimalkan.
Jika Anda perlu menggunakan fold() untuk mengurangi jumlah penjelajah atas nama langkah-langkah selanjutnya, cobalah untuk memesan operasi Anda sehingga yang paling murah menempati bagian kueri yang tidak dioptimalkan.
Pengaturan Kardinalitas
Kardinalitas default untuk properti simpul di Neptunus diatur, yang berarti bahwa ketika menggunakan mergeV () nilai yang diberikan dalam peta semuanya akan diberikan kardinalitas itu. Untuk menggunakan kardinalitas tunggal, Anda harus eksplisit dalam penggunaannya. Mulai dari TinkerPop 3.7.0, ada sintaks baru yang memungkinkan kardinalitas disediakan sebagai bagian dari peta seperti yang ditunjukkan pada contoh berikut:
g.mergeV([(T.id): '1234']). option(onMatch, ['age': single(20), 'name': single('alice'), 'city': set('miami')])
Atau, Anda dapat mengatur kardinalitas sebagai default untuk itu option sebagai berikut:
// age and name are set to single cardinality by default g.mergeV([(T.id): '1234']). option(onMatch, ['age': 22, 'name': 'alice', 'city': set('boston')], single)
Ada lebih sedikit opsi untuk mengatur kardinalitas mergeV() sebelum versi 3.7.0. Pendekatan umum adalah kembali ke property() langkah sebagai berikut:
g.mergeV([(T.id): '1234']). option(onMatch, sideEffect(property(single,'age', 20). property(set,'city','miami')).constant([:]))
catatan
Pendekatan ini hanya akan bekerja mergeV() ketika digunakan dengan langkah awal. Oleh karena itu, Anda tidak akan dapat berrantai mergeV() dalam satu traversal karena langkah pertama mergeV() setelah awal yang menggunakan sintaks ini akan menghasilkan kesalahan jika traverser yang masuk menjadi elemen grafik. Dalam hal ini, Anda ingin memecah mergeV() panggilan Anda menjadi beberapa permintaan di mana masing-masing dapat menjadi langkah awal.