Dezvoltarea subgrafului, Partea 2: Manipularea matricelor și identificarea entităților

(ProtoFire.io)

(Partea 1 ) | Partea 2

Această postare de blog oferă recomandări practice despre cum să utilizați eficient matricile și să generați ID-uri de entitate unice și referențiale.

În prima parte a acestei serii, am oferit o prezentare generală a subgrafelor pentru a ajuta dezvoltatorii să înțeleagă structura lor de bază. În plus, ne-am împărtășit ideile noastre pentru cartografierea și agregarea datelor.

De această dată, vom discuta alte două subiecte: gestionarea matricelor și generarea ID-urilor pentru entități care sunt atât unice, cât și ușor de referit. Ca parte a discuției, vom oferi recomandările noastre cu privire la modul de gestionare eficientă a matricelor și denumirea corectă a entităților.

Gestionarea eficientă a matricelor

Adăugarea matricelor la entități este utilă în anumite scenarii. De exemplu, există cazuri în care trebuie să modelăm o listă de adrese pentru o sursă de date sau să urmărim modificările istorice pentru un anumit câmp de-a lungul timpului.

Fără cunoștințe prealabile despre modul în care funcționează matricele în cadrul subgrafelor, am putea lua în considerare crearea unui câmp de tip matrice pe o definiție a tipului de entitate (în cadrul fișierului schema.graphql) și inițializarea unei matrice goale ori de câte ori este creată o nouă entitate de același tip. Când se adaugă date noi în matrice, putem împinge datele și salvăm entitatea. Deși sună intuitiv, din păcate nu funcționează.

Manipularea manuală a matricelor pe subgrafe, în special în scenariul de mai sus, are câteva avertismente. Ori de câte ori accesați o matrice a unei entități, ceea ce obțineți de fapt este o copie a matricei. Astfel, dacă adăugați date noi și salvați entitatea, aceasta nu va funcționa așa cum v-ați aștepta, deoarece pur și simplu modificați o copie a matricei, în timp ce originalul este lăsat neschimbat.

Pentru a actualiza matricea reală, putem plasa copia matricei într-o variabilă și apoi să modificăm datele. Apoi, putem seta variabila ca noua matrice a entității. În acest fel, vechea matrice este înlocuită de copie. Acest proces de actualizare a matricei este exemplificat în următorul cod.

// This won"t work
entity.numbers.push(BigInt.fromI32(1))
entity.save()// This will work
let numbers = entity.numbers
numbers.push(BigInt.fromI32(1))
entity.numbers = numbers
entity.save()

Deși puteți actualiza o matrice în modul demonstrat mai sus, nu este o soluție ideală . În afară de a fi incomod, există un alt motiv pentru a nu gestiona manual matricele – interogări de călătorie în timp. (Citiți partea 1 a seriei pentru a afla mai multe despre interogările de călătorie în timp.)

Este posibilă doar efectuarea de interogări de călătorie în timp, deoarece subgrafele țin evidența tuturor modificărilor din toate entitățile prezente toate timp. Dacă există o mulțime de entități cu câmpuri de matrice, care sunt mari și actualizate des, va trebui să fie stocate și copii ale tuturor matricelor. Acest lucru va avea un impact asupra performanței și spațiului pe disc al oricărui indexator care indexează subgraful dvs.

În prezent, serviciul găzduit al graficului este singurul indexator activ disponibil. În viitor, mai mulți indexatori se pot alătura cu adăugarea rețelei descentralizate a The Graph. Acești noi indexatori vor putea alege ce subgrafe să indexeze. Dacă subgraful dvs. este slab optimizat din cauza matricelor, probabil că nu va fi preluat de niciun indexer.

Pentru a optimiza matricele noastre, putem folosi @derivedFrom adnotare. Această metodă permite ca orice câmp matrice definit într-un tip de entitate să fie completat automat de toate entitățile de tipul specificat legate de entitatea pe care o definim. Următorul exemplu ilustrează utilizarea adnotării @derivedFrom.

type User @entity {
id: ID! positions: [Position!]! @derivedFrom(field: “user”)
}type Position @entity {
id: ID! user: User! # This is the ID String of the User
}

În exemplul de mai sus, avem un utilizator cu o listă generată automat cu entitățile Position. Ori de câte ori subgraful nostru primește o interogare care solicită câmpul de poziții al entității User, subgraful efectuează o căutare inversă pentru toate entitățile de tip Position conectat la entitatea User specifică din câmpul lor user. În acest mod, entitățile legate sunt cele care au ID-ul șirului altor entități într-unul din câmpurile sale.

Utilizând adnotarea @derivedFrom, putem defini entitatea introduceți datele pe care le dorim pentru datele noastre de matrice, definiți câmpul utilizat la obținerea matricei și conectați-l la entitatea originală prin ID-ul lor. Există, de asemenea, avantajul de a putea adăuga mai multe date (de exemplu, crearea sau actualizarea metadatelor) entităților care reprezintă datele matricei. Deoarece acestea sunt entități cu drepturi depline, le putem actualiza cu ușurință încărcându-le ID-urile în loc să le căutăm în matrice.

În timp ce gestionăm tablouri cu adnotarea @derivedFrom este mai ușor, mai sunt câteva considerații de care să știți.În primul rând, va funcționa numai cu relații de la unu la mai mulți. În relațiile multe-la-multe, avem încă nevoie de o parte a ecuației pentru a gestiona manual matricea. În al doilea rând, nu veți putea accesa datele matricei, în timp ce subgraful este indexat, deoarece matricea este completată atunci când este interogată.

Crearea unei denumiri convenție pentru ID-urile entității

Toate entitățile definite în fișierul schema.graphql sunt identificate printr-un câmp ID care este declarat ca un tip ID! reprezentat ca un șir. Câmpul ID este important deoarece este folosit pentru a încărca, crea și salva entități.

Deoarece câmpul ID este mijlocul principal de identificare a unei entități, acesta ar trebui să fie întotdeauna unic. Acestea fiind spuse, garantarea unicității unui ID nu este dificilă. Datele prezente în timpul indexului pot fi combinate pentru a genera ID-uri unice. Următorul cod este un exemplu în acest sens.

event.transaction.hash.toHex() + "-" + 
event.logIndex.toString()

Luând hash-ul tranzacției unui eveniment (unic pentru diferite tranzacții) și adăugându-l la indexul jurnalului pentru evenimentul particular (care identifică un eveniment în cadrul unei tranzacții), putem genera un ID compus unic. În acest fel, putem identifica o anumită entitate printre alte entități de același tip, cu condiția să se creeze o singură entitate pentru orice eveniment. Dacă este necesar, putem adăuga și mai multe date pentru a identifica în mod unic orice număr de entități create în același eveniment. De exemplu, am putea seta un contor pentru fiecare dată când se creează o entitate și să adăugăm valoarea la entitatea nou creată.

Deși este convenabil să aveți o metodă ușoară pentru generarea ID-urilor unice pentru entitățile noastre, ar trebui, de asemenea, să depuneți eforturi pentru a genera ID-uri care sunt previzibile și care pot fi referite. Dacă avem entități legate de o parte a domeniului nostru care este probabil să fie interogată de utilizatorii finali prin ID-ul lor, putem genera un ID care să facă referire la domeniul la care lucrăm.

De exemplu, luați în considerare un scenariu în care creăm o entitate Account pe un subgraf DEX. Această entitate Account va stoca soldul utilizatorului, precum și alte informații. Dacă creăm ID-ul entității pe baza hash-ului tranzacției, utilizatorul ar putea căuta în primul rând tranzacția care l-a creat și îl poate recrea, dar nu va fi intuitiv. O alternativă mai bună ar fi crearea unui ID bazat pe adresa Ethereum a utilizatorului și, dacă este necesar, combinarea acestuia cu altceva relevant pentru domeniu. În acest fel, putem identifica în mod unic un anumit cont de utilizator din alte conturi ale aceluiași utilizator.

În rezumat, ID-urile unice generice fără date specifice domeniului pot fi utile pentru entitățile care nu vor fi actualizate constant. Acest lucru este ideal pentru entitățile create pentru a salva metadatele pentru evenimente specifice domeniului care vor fi consumate dintr-o matrice derivată a unei entități principale. De exemplu, ID-urile unice generice sunt mai potrivite pentru transferuri, monete, arsuri și swap-uri.

Pe de altă parte, ID-urile specifice domeniului sunt ideale pentru entitățile principale și orice altă entitate care va primi actualizări frecvente. Este probabil să utilizați o combinație între o adresă Ethereum și alte ID-uri specifice domeniului. În majoritatea cazurilor, un contract inteligent va genera ID-uri unice și le va conecta la evenimente. Dacă nu este cazul, va trebui să studiați contractul inteligent și să identificați ce face entitatea dvs. unică și să utilizați aceste date pentru a genera un ID.

Ca notă laterală, și toHexString() – utilizate în mod obișnuit pentru a genera ID-uri din adrese sau hashuri – returnează un șir minuscul. Aceasta înseamnă că, atunci când interogați un subgraf pentru entități, șirul de identificare furnizat ar trebui să fie cu litere mici, deoarece interogarea este diferențiată de majuscule și minuscule.

Pentru mai multe informații despre dezvoltarea subgrafului, consultați documentație oficială . Detalii suplimentare pot fi găsite și în depozitul GitHub al proiectului . Graficul are, de asemenea, o comunitate activă și în creștere, pregătită să ajute și să răspundă la întrebările care apar. Îi încurajăm pe oricine este interesat să-și dezvolte propriile subgrafe să se alăture serverului Discord al graficului .

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *