Membuat peningkatan yang efisien dengan mergeV() Gremlin dan langkah-langkah mergeE() - Amazon Neptune

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

Membuat peningkatan yang efisien dengan mergeV() Gremlin dan langkah-langkah mergeE()

Upsert (atau sisipan bersyarat) menggunakan kembali simpul atau tepi jika sudah ada, atau membuatnya jika tidak. Upserts yang efisien dapat membuat perbedaan yang signifikan dalam kinerja kueri Gremlin.

Upserts memungkinkan Anda untuk menulis operasi penyisipan idempoten: 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 memutar kembali dengan aConcurrentModificationException, sehingga memerlukan percobaan ulang.

Misalnya, kueri berikut meningkatkan simpul dengan menggunakan yang disediakan Map untuk pertama kali mencoba menemukan simpul dengan a 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'])

Batching upserts untuk meningkatkan throughput

Untuk skenario penulisan throughput tinggi, Anda dapat berantai mergeV() dan mergeE() melangkah bersama untuk meningkatkan simpul dan tepi dalam batch. Batching mengurangi overhead transaksional untuk menaikkan sejumlah besar simpul dan tepi. Anda kemudian dapat lebih meningkatkan throughput dengan meningkatkan permintaan batch secara paralel menggunakan beberapa klien.

Sebagai aturan praktis, kami merekomendasikan untuk meningkatkan sekitar 200 catatan per permintaan batch. Rekaman adalah satu titik atau label tepi atau properti. Sebuah simpul dengan label tunggal dan 4 properti, misalnya, membuat 5 catatan. Tepi dengan label dan properti tunggal menciptakan 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 untuk berada di sisi yang aman, cobalah untuk memastikan bahwa permintaan Anda mengandung 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 (lihat). Membuat Penulisan Gremlin Multithreaded yang Efisien Jumlah klien harus sama dengan jumlah thread pekerja pada instance penulis Neptunus Anda, yang biasanya 2 x vCPUs jumlah di server. Misalnya, sebuah r5.8xlarge instance memiliki 32 vCPUs dan 64 thread pekerja. Untuk skenario penulisan throughput tinggi menggunakanr5.8xlarge, Anda akan menggunakan 64 klien yang menulis batch upserts 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 disuplai dengan aliran permintaan yang stabil yang menempati semua thread pekerja tanpa membanjiri antrian permintaan sisi server (lihat). Mengukur instans DB dalam sebuah klaster Neptune DB

Cobalah untuk menghindari langkah-langkah yang menghasilkan banyak pelintas

Ketika langkah Gremlin dijalankan, dibutuhkan traverser masuk, dan memancarkan satu atau lebih traverser keluaran. Jumlah pelintas yang dipancarkan oleh satu langkah menentukan berapa kali langkah berikutnya dijalankan.

Biasanya, ketika melakukan operasi batch Anda ingin setiap operasi, seperti upsert vertex A, untuk mengeksekusi sekali, sehingga urutan operasi terlihat seperti ini: upsert vertex A, kemudian upsert vertex B, kemudian upsert vertex C, dan seterusnya. Selama sebuah langkah membuat atau memodifikasi hanya satu elemen, ia hanya memancarkan satu traverser, dan langkah-langkah yang mewakili operasi berikutnya dijalankan hanya sekali. Jika, di sisi lain, sebuah operasi membuat atau memodifikasi lebih dari satu elemen, ia memancarkan beberapa pelintas, yang pada gilirannya menyebabkan langkah-langkah selanjutnya dieksekusi 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 yang tidak diinginkan, tepi atau nilai properti.

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 upserts dan sisipan cara menangani operasi yang dapat memancarkan banyak pelintas.

Menaikkan simpul

mergeV()Langkah ini dirancang khusus untuk menaikkan simpul. Dibutuhkan sebagai argumen a Map yang mewakili elemen untuk mencocokkan 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 penciptaan atau kecocokan, di mana option() modulator dapat diterapkan dengan Merge.onCreate dan Merge.onMatch token untuk mengontrol perilaku masing-masing. Lihat Dokumentasi TinkerPop Referensi untuk informasi lebih lanjut tentang cara menggunakan langkah ini.

Anda dapat menggunakan ID simpul untuk menentukan apakah ada simpul tertentu. Ini adalah pendekatan yang lebih disukai, karena Neptunus mengoptimalkan upserts untuk kasus penggunaan yang sangat bersamaan. IDs Sebagai contoh, kueri berikut membuat simpul dengan ID simpul yang diberikan jika belum ada, atau menggunakannya kembali jika memang demikian:

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 diakhiri 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 simpul 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 sendiri yang disediakan pengguna IDs untuk membuat simpul, dan gunakan ini IDs untuk menentukan apakah simpul ada selama operasi upsert. Ini memungkinkan Neptunus mengoptimalkan upserts. Upsert berbasis ID dapat secara signifikan lebih efisien daripada upsert berbasis properti ketika modifikasi bersamaan adalah umum.

Bagian atas simpul berantai

Anda dapat menghubungkan bagian atas simpul bersama-sama untuk menyisipkannya dalam 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 penelusuran yang berlebihan untuk pencarian dasarid, itu tidak seefisien kueri sebelumnya.

Tepi yang menjulang

mergeE()Langkah ini dirancang khusus untuk menaikkan tepi. Dibutuhkan Map sebagai argumen yang mewakili elemen untuk mencocokkan 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 penciptaan atau kecocokan, di mana option() modulator dapat diterapkan dengan Merge.onCreate dan Merge.onMatch token untuk mengontrol perilaku masing-masing. Lihat Dokumentasi TinkerPop Referensi untuk informasi lebih lanjut tentang cara menggunakan langkah ini.

Anda dapat menggunakan tepi IDs untuk menaikkan tepi dengan cara yang sama Anda menaikkan simpul menggunakan simpul kustom. IDs 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 simpul Direction.from dan Direction.to simpul jika perlu membuat tepi baru: IDs

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 diakhiri 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 edge kembali ke klien, yang membantu mengurangi biaya penguncian kueri.

Banyak aplikasi menggunakan simpul khususIDs, tetapi meninggalkan Neptunus untuk menghasilkan tepi. IDs Jika Anda tidak tahu ID tepi, tetapi Anda tahu from dan to simpulnyaIDs, 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.

Bagian atas tepi rantai

Seperti halnya vertex upserts, sangat mudah untuk menggabungkan 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 vertex dan edge upserts

Terkadang Anda mungkin ingin meningkatkan kedua simpul dan tepi yang menghubungkannya. Anda dapat mencampur contoh batch yang disajikan di sini. Contoh berikut meningkatkan 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 upserts dan sisipan

Terkadang Anda mungkin ingin meningkatkan kedua simpul dan tepi yang menghubungkannya. Anda dapat mencampur contoh batch yang disajikan di sini. Contoh berikut meningkatkan 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 satu traverser, 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 potensi jumlah pelintas yang dipancarkan dari setiap operasi.

Perhatikan contoh berikut, yang mencampur upsert 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 FOLLOWED tepi dan 3 VISITED tepi. Namun, kueri sebagai tertulis menyisipkan 8 tepi: 2 FOLLOWED dan 6VISITED. Alasan untuk ini adalah bahwa operasi yang menyisipkan 2 FOLLOWED tepi memancarkan 2 pelintas, 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 FOLLOWED tepi. Ini menghasilkan traverser tunggal, yang kemudian menyebabkan operasi berikutnya dieksekusi hanya sekali.

Kelemahan dari pendekatan ini adalah bahwa query sekarang tidak sepenuhnya dioptimalkan, karena tidak fold() dioptimalkan. Operasi insert yang mengikuti sekarang juga tidak fold() akan dioptimalkan.

Jika Anda perlu menggunakan fold() untuk mengurangi jumlah pelintas 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 diberikan 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 menetapkan 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 dengan mergeV() ketika digunakan dengan langkah awal. Oleh karena itu Anda tidak akan dapat berantai mergeV() dalam satu traversal karena yang pertama mergeV() setelah langkah 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.