{"id":75530,"date":"2020-03-26T19:42:23","date_gmt":"2020-03-26T17:42:23","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/vyvod-rezultatov-poiska-i-problemy-s-proizvoditelnostyu"},"modified":"2020-03-26T19:42:23","modified_gmt":"2020-03-26T17:42:23","slug":"vyvod-rezultatov-poiska-i-problemy-s-proizvoditelnostyu","status":"publish","type":"post","link":"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/vyvod-rezultatov-poiska-i-problemy-s-proizvoditelnostyu","title":{"rendered":"Otsingutulemuste v\u00e4ljund ja j\u00f5udlusprobleemid","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>\u00dcks t\u00fc\u00fcpiline stsenaarium, millega me oma rakendustes kokku puutume, on andmete otsimine teatud kriteeriumide alusel ja nende kuvamine lugemiseks mugaval viisil. Samuti v\u00f5ivad olla lisav\u00f5imalused, nagu sortimine, r\u00fchmitamine ja lehek\u00fcljed. \u00dclesanne n\u00e4ib esmapilgul triviaalne, kuid selle lahendamisel teevad paljud arendajad mitmeid vigu, mis m\u00f5jutavad hiljem j\u00f5udlust. Proovime vaadata erinevaid lahenduste variante ja formuleerida soovitusi, kuidas valida t\u00f5husaim rakenduse t\u00e4ideviimine.<\/p>\n<p><img decoding=\"async\" alt=\"Otsingutulemuste v\u00e4ljund ja j\u00f5udlusprobleemid\" src=\"\/wp-content\/uploads\/2020\/03\/364ab29c4a6117ff441b933a38ec8401.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Lehek\u00fcljendamise variant #1<\/h2>\n<p>\nLihtsaim variant, mis p\u00e4he tuleb, on postitada otsingu tulemused klassikalisel viisil lehek\u00fcljendatult.<\/p>\n<p><img decoding=\"async\" alt=\"Otsingutulemuste v\u00e4ljund ja j\u00f5udlusprobleemid\" src=\"\/wp-content\/uploads\/2020\/03\/4957d9ad21a8a0c70390b224fe76cb33.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nOletame, et rakenduses kasutatakse relationaalset andmebaasi. Sel juhul peab sellise vormingu jaoks toimuma kaks SQL p\u00e4ringut:<\/p>\n<ul>\n<li>Saama read praegusele lehek\u00fcljele.<\/li>\n<li>Arvutama v\u00e4lja koguarvu read, mis vastavad otsingukriteeriumidele \u2014 see on vajalik lehtede n\u00e4itamiseks.<\/li>\n<\/ul>\n<p>\nVaadakem esimest p\u00e4ringut testimise MS SQL andmebaasi p\u00f5hjal <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/Microsoft\/sql-server-samples\/releases\/download\/adventureworks\/AdventureWorks2016_EXT.bak\">AdventureWorks <\/a><\/noindex>2016 serveri jaoks. Selleks kasutame tabelit Sales.SalesOrderHeader:<\/p>\n<pre><code class=\"sql\">SELECT * FROM Sales.SalesOrderHeader\nORDER BY OrderDate DESC\nOFFSET 0 ROWS\nFETCH NEXT 50 ROWS ONLY\n<\/code><\/pre>\n<p>\n\u00dclaltoodud p\u00e4ring kuvab esimesed 50 tellimust loendist, mis on sorteeritud lisamise kuup\u00e4eva j\u00e4rgi, teisis\u00f5nu \u2014 50 viimast tellimust.<\/p>\n<p>K\u00e4ib see testimise andmebaasis kiiresti, kuid vaatame, mis juhtub plaaniga ja sisend-v\u00e4ljund statistikaga:<\/p>\n<p><img decoding=\"async\" alt=\"Otsingutulemuste v\u00e4ljund ja j\u00f5udlusprobleemid\" src=\"\/wp-content\/uploads\/2020\/03\/248e4b64593c7000216b46777183d639.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<pre><code class=\"plaintext\">Tabel 'SalesOrderHeader'. Skaneeringute arv 1, loogilised lugemised 698, f\u00fc\u00fcsilised lugemised 0, eelnevad lugemised 0, lob loogilised lugemised 0, lob f\u00fc\u00fcsilised lugemised 0, lob eelnevad lugemised 0.<\/code><\/pre>\n<p>\n<i>Iga p\u00e4ringu sisend-v\u00e4ljund statistika saamiseks saab k\u00e4ivitada p\u00e4ringute keskkonnas k\u00e4su SET STATISTICS IO ON.<\/i><\/p>\n<p>Nagu t\u00e4itmisplaanist n\u00e4ha, on k\u00f5ige ressursimahukam kogu algsete tabeli ridade sortimine lisamise kuup\u00e4eva j\u00e4rgi. Probleem on siiski selles, et mida rohkem ridu tabelisse lisandub, seda 'raskem' on sortimine. Praktiliselt tuleks selliseid olukordi v\u00e4ltida, seet\u00f5ttu lisame sortimisekuva kuup\u00e4evale indeksi ja vaatame, kas ressursikasutus on muutunud:<\/p>\n<p><img decoding=\"async\" alt=\"Otsingutulemuste v\u00e4ljund ja j\u00f5udlusprobleemid\" src=\"\/wp-content\/uploads\/2020\/03\/a33e1eadf6f8f8b516b9bb834ad7ad86.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<pre><code class=\"plaintext\">Tabel 'SalesOrderHeader'. Skaneeringute arv 1, loogilised lugemised 165, f\u00fc\u00fcsilised lugemised 0, eelnevad lugemised 5, lob loogilised lugemised 0, lob f\u00fc\u00fcsilised lugemised 0, lob eelnevad lugemised 0.\n<\/code><\/pre>\n<p>\nIlmselt on asjad palju paremaks muutunud. Kuid kas k\u00f5ik probleemid on lahendatud? Muudame p\u00e4ringu tellimuste leidmiseks, kus kaupade koguhind \u00fcletab 100 dollarit:<\/p>\n<pre><code class=\"sql\">SELECT * FROM Sales.SalesOrderHeader\nWHERE SubTotal &gt; 100\nORDER BY OrderDate DESC\nOFFSET 0 ROWS\nFETCH NEXT 50 ROWS ONLY\n<\/code><\/pre>\n<p>\n<img decoding=\"async\" alt=\"Otsingutulemuste v\u00e4ljund ja j\u00f5udlusprobleemid\" src=\"\/wp-content\/uploads\/2020\/03\/e057bfc89e11a31c6d2855b93ec3c747.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<pre><code class=\"plaintext\">Tabel 'SalesOrderHeader'. Skaneerimise arv 1, loogilised lugemised 1081, f\u00fc\u00fcsilised lugemised 0, lugemise eelvaated 0, lob loogilised lugemised 0, lob f\u00fc\u00fcsilised lugemised 0, lob lugemise eelvaated 0.<\/code><\/pre>\n<p>\nK\u00e4es on naljakas olukord: p\u00e4ringu plaan ei ole palju halvem eelmisest, kuid tegelik loogiliste lugemiste arv on peaaegu kaks korda suurem kui kogu tabeli skaneerimise korral. Lahendus on olemas \u2014 kui olemasolevast indeksist teha kombineeritud ja teiseks v\u00e4ljaks lisada kaupade koguhind, saame j\u00e4lle 165 loogilist lugemist:<\/p>\n<pre><code class=\"sql\">CREATE INDEX IX_SalesOrderHeader_OrderDate_SubTotal ON Sales.SalesOrderHeader(OrderDate, SubTotal);\n<\/code><\/pre>\n<p>\nSeda n\u00e4idete seeriat saab j\u00e4tkata veel kaua, kuid kaks peamist m\u00f5tet, mida siin soovin v\u00e4ljendada, on j\u00e4rgmised:<\/p>\n<ul>\n<li>Iga uue kriteeri v\u00f5i sortimisj\u00e4rjestuse lisamine p\u00e4ringusse v\u00f5ib oluliselt m\u00f5jutada selle t\u00e4itmise kiirus.<\/li>\n<li>Kuid kui me peame v\u00e4lja v\u00f5tma ainult osa andmetest, mitte k\u00f5iki otsingutingimustele vastavaid tulemusi \u2014 on palju viise, kuidas sellist p\u00e4ringut optimeerida.<\/li>\n<\/ul>\n<p>\nN\u00fc\u00fcd liigume teise p\u00e4ringu juurde, mida mainiti alguses \u2014 selle juurde, mis loendab rekordite arvu, mis vastavad otsingutingimustele. V\u00f5tame sama n\u00e4ite \u2014 otsing tellimuste leidmiseks, mis maksavad rohkem kui 100 dollarit:<\/p>\n<pre><code class=\"sql\">SELECT COUNT(1) FROM Sales.SalesOrderHeader\nWHERE SubTotal &gt; 100\n<\/code><\/pre>\n<p>\nKui vastata sellele koostatud indeksiga, saame:<\/p>\n<p><img decoding=\"async\" alt=\"Otsingutulemuste v\u00e4ljund ja j\u00f5udlusprobleemid\" src=\"\/wp-content\/uploads\/2020\/03\/7beab0c83a50e2d68a83a965df555ec9.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<pre><code class=\"plaintext\">Tabel 'SalesOrderHeader'. Skaneeringute arv 1, loogilised lugemised 698, f\u00fc\u00fcsilised lugemised 0, eelnevad lugemised 0, lob loogilised lugemised 0, lob f\u00fc\u00fcsilised lugemised 0, lob eelnevad lugemised 0.<\/code><\/pre>\n<p>\nEt p\u00e4ring l\u00e4bib kogu indeksi, ei ole \u00fcllatav, kuna v\u00e4li SubTotal ei ole esimeses positsioonis, seega ei saa p\u00e4ring seda \u00e4ra kasutada. Probleem lahendatakse lisades veel \u00fche indeksi v\u00e4ljale SubTotal, mis annab kokku juba vaid 48 loogilist lugemist.<\/p>\n<p>V\u00f5in tuua veel m\u00f5ned n\u00e4ited p\u00e4ringute jaoks, mis loendavad arvu, kuid p\u00f5him\u00f5te j\u00e4\u00e4b samaks: <b>andmete kogumise ja koguarvu arvestamine \u2014 need on kaks fundamentaalselt erinevat p\u00e4ringut<\/b>, ja iga\u00fcks n\u00f5uab oma meetmeid optimeerimiseks. \u00dcldiselt ei ole v\u00f5imalik leida indeksite kombinatsiooni, mis t\u00f6\u00f6tab sama h\u00e4sti m\u00f5lema p\u00e4ringu jaoks.<\/p>\n<p>Seega, \u00fcks olulisemaid n\u00f5udeid, mida tuleb sellise otsingulahenduse arendamisel t\u00e4psustada, on see, kas ettev\u00f5ttele on oluline n\u00e4ha leitud objektide koguarvu. Sageli ei ole see nii. Ja navigeerimine konkreetsete lehek\u00fclgede numbrite vahel on minu arvates lahendus, millel on v\u00e4ga kitsas rakendamisala, kuna enamiku lehek\u00fclgede vahetamise stsenaariumide puhul on see pigem \"mine j\u00e4rgmisele lehele\".<\/p>\n<h2>Lehek\u00fclgede vahetamise variant #2<\/h2>\n<p>\nOletame, et kasutajatele ei ole \u00fcldise leitud objektide arvu teadmine oluline. Proovime lihtsustada otsingulehte:<\/p>\n<p><img decoding=\"async\" alt=\"Otsingutulemuste v\u00e4ljund ja j\u00f5udlusprobleemid\" src=\"\/wp-content\/uploads\/2020\/03\/66f5ee6dc1a52f14e55ae31e05c502b2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nFakt on, et muutunud on ainult see, et ei ole v\u00f5imalik liikuda konkreetsete lehek\u00fclgede numbrite vahel ning n\u00fc\u00fcd ei pea sellele tabelile teadma, kui palju lehek\u00fclgi kokku v\u00f5ib olla. Kuid tekib k\u00fcsimus \u2014 kuidas tabel saab teada, kas j\u00e4rgmise lehek\u00fclje andmed on olemas (et \u00f5igesti n\u00e4idata linki \u201eJ\u00e4rgmine\u201d)?<\/p>\n<p>Vastus on v\u00e4ga lihtne: andmebaasist saab lugeda \u00fche kirje rohkem, kui on vaja kuvada, ja see \"lisakirje\" n\u00e4itabki, kas j\u00e4rgmine partii on olemas. Seega, et saada \u00fchte andmelehte, tuleb teha vaid \u00fcks p\u00e4ring, mis oluliselt parandab j\u00f5udlust ja lihtsustab sellise funktsionaalsuse toetust. Minu praktikas oli juhtum, kus koguarvu arvestamisest loobumine kiirendas tulemuste v\u00e4ljundit 4-5 korda.<\/p>\n<p>Selle l\u00e4henemise jaoks on olemas mitmeid kasutajaliidese valikuid: k\u00e4sklused \u201etagasi\u201d ja \u201eedasi\u201d, nagu eelnevas n\u00e4ites, nupp \u201elae veel\u201d, mis lihtsalt lisab uue partii kuvatud tulemustele, \u201el\u00f5pmatu kerimine\u201d, mis toimib \u201elae veel\u201d p\u00f5him\u00f5tte j\u00e4rgi, kuid j\u00e4rgmise partii saamise signaaliks on kasutaja kerimine k\u00f5ikide kuvatud tulemusteni l\u00f5puni. \u00dcksk\u00f5ik, milline on visuaalne lahendus, j\u00e4\u00e4b andmete valimise p\u00f5him\u00f5te samaks.<\/p>\n<h2>Lehek\u00fclgede vahetamise rakendamise n\u00fcansid<\/h2>\n<p>\nK\u00f5igis \u00fclaltoodud p\u00e4ringute n\u00e4idetes kasutatakse l\u00e4henemist \u201esilmus + arv\u201d, kus p\u00e4ringus m\u00e4rgitakse \u00e4ra, millise j\u00e4rjekorra j\u00e4rgi tulemus ja kui palju ridu tuleb tagastada. Esiteks vaatame, kuidas on parim korraldada parameetrite edastamine sellisel juhul. Praktikas olen kohanud mitmeid viise:<\/p>\n<ul>\n<li>Soovitava lehe j\u00e4rjestusnumber (pageIndex), lehe suurus (pageSize).<\/li>\n<li>Esimese salvestuse j\u00e4rjestusnumber, mille me saame (startIndex), maksimaalne salvestuste arv tulemuses (count).<\/li>\n<li>Esimese salvestuse j\u00e4rjestusnumber, mille me salvestame (startIndex), viimase salvestuse j\u00e4rjestusnumber, mille me salvestame (endIndex).<\/li>\n<\/ul>\n<p>\nEsmapilgul v\u00f5ib tunduda, et see on nii elementaarne, et mingit vahet pole. Kuid see ei ole nii \u2014 k\u00f5ige mugavam ja universaalsem variant on teine (startIndex, count). Sellel on mitu p\u00f5hjust:<\/p>\n<ul>\n<li>Selle l\u00e4henemise puhul, kus loetakse +1 salvestust, on esimene variant pageIndex ja pageSize \u00e4\u00e4rmiselt ebamugav. N\u00e4iteks tahame lehe peal kuvada 50 salvestust. Vastavalt eelmisele algoritmile tuleb lugeda \u00fche salvestuse v\u00f5rra rohkem, kui tegelikult on vajalik. Kui see \u201e+1\u201c pole serveris ette n\u00e4htud, siis selgub, et esimese lehe jaoks peame k\u00fcsima salvestusi vahemikus 1 kuni 51, teise jaoks \u2014 51 kuni 101 jne. Kui m\u00e4\u00e4rata lehe suuruseks 51 ja suurendada pageIndex, siis teine leht tagastab salvestused vahemikus 52 kuni 102 jne. Seega on esimese variandi puhul ainus viis korralikult rakendada j\u00e4rgmise lehe juurde mineku nuppu \u2014 ette n\u00e4ha serveris \u201e\u00fche liigse\u201c rea lugemist, mis on v\u00e4ga ebaselge n\u00fcanss.<\/li>\n<li>Kolmas variant pole \u00fcldse m\u00f5istlik, kuna enamikus andmebaasides tuleb p\u00e4ringute tegemiseks edastada ikkagi arv, mitte viimase salvestuse indeks. Olgu see startIndex lahutamine endIndex'ist ja elementaarne aritmeetiline tehe, kuid see on siinkohal \u00fcleliigne.<\/li>\n<\/ul>\n<p>\nN\u00fc\u00fcd tuleks kirjeldada puudusi rakendamisel, mis kasutab \u201enihet + kogust\u201c:<\/p>\n<ul>\n<li>Iga j\u00e4rgmise lehe saamine osutub kallimaks ja aeglasemaks kui eelmine, kuna andmebaas peab ikkagi l\u00e4bi lugema k\u00f5ik salvestused \u201ealgusest\u201c vastavalt otsingukriteeriumidele ja sortimisele ning seej\u00e4rel peatuma vajalikul fragmendil.<\/li>\n<li>Kaugeltki mitte k\u00f5ik andmebaaside haldamise s\u00fcsteemid (\u0421\u0423\u0411\u0414) ei pruugi seda l\u00e4henemist toetada.<\/li>\n<\/ul>\n<p>\nAlternatiive on, kuid needki ei ole ideaalsed. Esimene nendest l\u00e4henemistest nimetatakse \u201ekeyset paging\u201d v\u00f5i \u201eseek method\u201d ja see seisneb j\u00e4rgmisest: p\u00e4rast andmeportsjoni saamist saab salvestada viimasel lehel olevate salvestuste v\u00e4ljade v\u00e4\u00e4rtused ja seej\u00e4rel kasutada neid j\u00e4rgmise portsjoni saamiseks. N\u00e4iteks sooritasime sellise p\u00e4ringu:<\/p>\n<pre><code class=\"sql\">SELECT * FROM Sales.SalesOrderHeader\nORDER BY OrderDate DESC\nOFFSET 0 ROWS\nFETCH NEXT 50 ROWS ONLY\n<\/code><\/pre>\n<p>\nJa viimases kirjas saime tellimuse kuup\u00e4eva v\u00e4\u00e4rtuseks '2014-06-29'. Sel juhul saab j\u00e4rgmise lehe saamiseks proovida teha j\u00e4rgmist:<\/p>\n<pre><code class=\"sql\">SELECT * FROM Sales.SalesOrderHeader\nWHERE OrderDate &lt; &#039;2014-06-29&#039;\nORDER BY OrderDate DESC\nOFFSET 0 ROWS\nFETCH NEXT 50 ROWS ONLY\n<\/code><\/pre>\n<p>\nProbleem on selles, et OrderDate ei ole ainulaadne v\u00e4li ja \u00fclaltoodud tingimus l\u00f5petab t\u00f5en\u00e4oliselt paljude vajalike ridade vahelej\u00e4tmise. Selle p\u00e4ringu selguse tagamiseks tuleb tingimusele lisada ainulaadne v\u00e4li (eeldame, et 75074 on viimane esmane v\u00f5tme v\u00e4\u00e4rtus esimesest osast):<\/p>\n<pre><code class=\"sql\">SELECT * FROM Sales.SalesOrderHeader\nWHERE (OrderDate = '2014-06-29' AND SalesOrderID &lt; 75074)\n   OR (OrderDate &lt; &#039;2014-06-29&#039;)\nORDER BY OrderDate DESC, SalesOrderID DESC\nOFFSET 0 ROWS\nFETCH NEXT 50 ROWS ONLY\n<\/code><\/pre>\n<p>\nSee valik t\u00f6\u00f6tab korralikult, kuid \u00fcldiselt on seda keeruline optimeerida, kuna tingimus sisaldab OR operaatorit. Kui OrderDate'i suurenemisega suureneb ka esitlusuuringu primaarv\u00f5ti, siis saab tingimust lihtsustada, j\u00e4ttes alles ainult SalesOrderID filtri. Kuid kui primaarv\u00f5tme ja tulemuse j\u00e4rgi sorteeritud v\u00e4lja vahel ei ole ranget korrelatsiooni \u2014 enamikus andmebaasis\u00fcsteemides ei saa sellest OR-ist loobuda. Ainus, mida ma tean, on PostgreSQL, kus tuple v\u00f5rreldes t\u00e4ielikult toetatakse, ja \u00fclaltoodud tingimus v\u00f5ib olla kirjutatud kui \u201eWHERE (OrderDate, SalesOrderID) &lt; (&#039;2014-06-29&#039;, 75074)\u201d. Kui need kaks v\u00e4lja on koostisosade v\u00f5tmes, peaks selline p\u00e4ring olema piisavalt kerge.<\/p>\n<p>Teine alternatiivne l\u00e4henemine v\u00f5ib esineda n\u00e4iteks <noindex><a rel=\"nofollow\" href=\"https:\/\/www.elastic.co\/guide\/en\/elasticsearch\/reference\/6.8\/search-request-scroll.html\">ElasticSearch scroll API<\/a><\/noindex> v\u00f5i <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/@gary.strange\/understanding-cosmosdb-continuation-tokens-hasmoreresults-and-connectionpolicy-requesttimeouts-3ed1fadfa81d\">Cosmos DB<\/a><\/noindex> \u2014 kus p\u00e4ring ei tagasta mitte ainult andmeid, vaid ka spetsiaalset identifikaatorit, mille abil saab saada j\u00e4rgmise andmepartii. Kui see identifikaator on piiramatu elueaga (nagu Cosmos DB-s), siis on see suurep\u00e4rane viis lehekeste j\u00e4rkj\u00e4rguliseks navigeerimiseks (\u00fclaltoodud variants #2). Selle v\u00f5imalikke puudusi: ei toetata kaugeltki k\u00f5igis andmebaaside haldamise s\u00fcsteemides; saadud j\u00e4rgmise partii identifikaatoril v\u00f5ib olla piiratud eluiga, mis \u00fcldjuhul ei sobi kasutajate interaktsiooni rakendamiseks (n\u00e4iteks ElasticSearch scroll API).<\/p>\n<h2>Kompleksne filtreerimine<\/h2>\n<p>\nT\u00e4itame \u00fclesannet veelgi keerulisemaks. Oletame, et on tekkinud n\u00f5ue rakendada nn faceted search, mida k\u00f5ik kindlasti tunnevad e-poodide kontekstis. \u00dclaltoodud n\u00e4ited tellimuste tabelist ei ole siin v\u00e4ga n\u00e4itlikud, seega l\u00fclitume AdventureWorks andmebaasi Product tabelisse:<\/p>\n<p><img decoding=\"async\" alt=\"Otsingutulemuste v\u00e4ljund ja j\u00f5udlusprobleemid\" src=\"\/wp-content\/uploads\/2020\/03\/070890a3cb79de3edc69b60b5300efe7.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMis on faceted search idee? See seisneb selles, et iga filtri elemendi jaoks n\u00e4idatakse vastava kriteeriumi kohta vastavate kirjeid arvu. <i>arvestades filtreid, mis on valitud k\u00f5igis teistes kategooriates.<\/i>.<\/p>\n<p>N\u00e4iteks, kui valime selles n\u00e4ites kategooria Bikes ja v\u00e4rvi Black, kuvab tabel ainult mustade v\u00e4rvi jalgrattaid, kuid samas:<\/p>\n<ul>\n<li>Iga \"Categories\" grupi kriteeriumi jaoks n\u00e4idatakse musta v\u00e4rvi tooteid, mis kuuluvad sellesse kategooriasse.<\/li>\n<li>Iga \"Colors\" grupi kriteeriumi jaoks n\u00e4idatakse mustade jalgrataste arvu.<\/li>\n<\/ul>\n<p>\nSiin on n\u00e4ide selliste tingimuste tulemuste v\u00e4ljundist:<\/p>\n<p><img decoding=\"async\" alt=\"Otsingutulemuste v\u00e4ljund ja j\u00f5udlusprobleemid\" src=\"\/wp-content\/uploads\/2020\/03\/7c8ec4d8b427f1f59f0129afebe74b08.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nKui lisaks valida kategooria \"Clothing\", kuvab tabel ka musta v\u00e4rvi riideid, mis on saadaval. Mustade toodete arvu \"Color\" sektsioonis arvutatakse samuti uute tingimuste j\u00e4rgi, ent \"Categories\" sektsioonis ei muutu midagi... Loodan, et need n\u00e4ited on piisavad, et m\u00f5ista tuttavat faceted searchi t\u00f6\u00f6korraldust.<\/p>\n<p>N\u00fc\u00fcd kujutame ette, kuidas seda relatsioonilises andmebaasis rakendada. Iga kriteeriumigrupp, nagu Category ja Color, vajab eraldi p\u00e4ringut:<\/p>\n<pre><code class=\"sql\">SELECT pc.ProductCategoryID, pc.Name, COUNT(1) FROM Production.Product p\n  INNER JOIN Production.ProductSubcategory ps ON p.ProductSubcategoryID = ps.ProductSubcategoryID\n  INNER JOIN Production.ProductCategory pc ON ps.ProductCategoryID = pc.ProductCategoryID\nWHERE p.Color = 'Black'\nGROUP BY pc.ProductCategoryID, pc.Name\nORDER BY COUNT(1) DESC\n<\/code><\/pre>\n<p>\n<img decoding=\"async\" alt=\"Otsingutulemuste v\u00e4ljund ja j\u00f5udlusprobleemid\" src=\"\/wp-content\/uploads\/2020\/03\/3b59b68ce934c4ec1630ec649e68ccdb.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<pre><code class=\"sql\">SELECT Color, COUNT(1) FROM Production.Product p\n  INNER JOIN Production.ProductSubcategory ps ON p.ProductSubcategoryID = ps.ProductSubcategoryID\nWHERE ps.ProductCategoryID = 1 --Bikes\nGROUP BY Color\nORDER BY COUNT(1) DESC\n<\/code><\/pre>\n<p>\n<img decoding=\"async\" alt=\"Otsingutulemuste v\u00e4ljund ja j\u00f5udlusprobleemid\" src=\"\/wp-content\/uploads\/2020\/03\/82e1e6ab0fae683d383e3fecf4e3a15a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nMis on valesti sellega lahendusega? V\u00e4ga lihtne \u2014 see ei skaala h\u00e4sti. Iga filtreerimisosakond n\u00f5uab eraldi p\u00e4ringut koguste arvestamiseks ja need p\u00e4ringud ei ole just kerged. E-poes v\u00f5ib m\u00f5nes kategoorias olla ka mitu tosinat filtreerimisosakonda, mis v\u00f5ib olla t\u00e4iendavaks probleemiks j\u00f5udlusest.<\/p>\n<p>Tavaliselt p\u00e4rast neid v\u00e4iteid pakuvad mulle m\u00f5ned lahendused, nimelt:<\/p>\n<ul>\n<li>Kombineeri k\u00f5ik koguse arvestused \u00fcheks p\u00e4ringuks. Tehniliselt on see v\u00f5imalik kasutada UNION v\u00f5tmes\u00f5na, kuid see ei paranda j\u00f5udlust \u2014 andmebaasil tuleb ikkagi iga osa \"nullist\" l\u00e4bi viia.<\/li>\n<li>Kata arvestused. Seda soovitatakse mulle peaaegu igal korral, kui ma probleemi kirjeldan. Detail on see, et see on \u00fcldiselt v\u00f5imatu. Oletame, et meil on 10 \"fasaadi\", milles igas on 5 v\u00e4\u00e4rtust. See on v\u00e4ga \"moderne\" olukord v\u00f5rreldes sellega, mida n\u00e4ha sama internetipoe puhul. \u00dche fasaadi elemendi valik m\u00f5jutab 9 teise koguseid, teisis\u00f5nu, iga kriteeriumi kombinatsiooni jaoks v\u00f5ivad kogused olla erinevad. Kokku on meie n\u00e4ites 50 kriteeriumi, mida kasutaja saab valida, seega on v\u00f5imalikke kombinatsioone 250. Sellise andmemassiivi t\u00e4itmiseks ei piisa ei m\u00e4lust ega ajast. Siin v\u00f5ib vastu vaielda ja \u00f6elda, et mitte k\u00f5ik kombinatsioonid ei ole reaalsed ja kasutaja valib harva rohkem kui 5-10 kriteeriumi. Jah, on v\u00f5imalik teha laisk laadimine ja koguste cache ainult nende jaoks, mida on kunagi valitud, kuid mida rohkem on valikuv\u00f5imalusi, seda v\u00e4hem efektiivne on selline cache ja seda silmatorkavamad on vastamise ajaga seotud probleemid (eriti kui andmekogum muutub regulaarselt).<\/li>\n<\/ul>\n<p>\n\u00d5nneks on sellisel \u00fclesandel juba ammu olemas piisavalt efektiivsed lahendused, mis ennustatavalt t\u00f6\u00f6tavad suurte andmemahtude poole. Iga \u00fchte neist variantidest on m\u00f5ttekas jagada fassaadide \u00fclearvutamine ja tulemuste lehe saamine kaheks paralleelseks p\u00e4ringuks serverisse ning korraldada kasutajaliides selliselt, et fassaadide andmete laadimine \"ei sega\" otsingutulemuste kuvamist.<\/p>\n<ul>\n<li>Kutsuge t\u00e4ielikku \"fassaadide\" \u00fcmberarvestust nii harva kui v\u00f5imalik. N\u00e4iteks, \u00e4rge arvutage k\u00f5ike iga otsingukriteeriumi muutmise korral, vaid leidke \u00fcldine vastuste arv, mis vastab praegustele tingimustele, ja pakkuda kasutajale nende kuvamist \u2014 \"leidub 1425 kirjet, n\u00e4idata?\" Kasutaja v\u00f5ib kas j\u00e4tkata otsingutingimuste muutmist v\u00f5i vajutada nuppu \u201en\u00e4ita\u201c. Alles teisel juhul tehakse k\u00f5ik p\u00e4ringud tulemuste saamiseks ja k\u00f5igi \"fassaadide\" arvu \u00fcmberarvestamiseks. Samuti tuleb silmas pidada, et tuleb tegeleda p\u00e4ringuga \u00fcldise vastuste arvu saamiseks ja selle optimeerimisega. Sellist meetodit v\u00f5ib leida paljudest v\u00e4ikestest veebipoodidest. On selge, et see ei ole imeravim, kuid lihtsates olukordades v\u00f5ib olla kokkuv\u00f5tteks hea kompromiss.<\/li>\n<li>Kasutage otsingumootoreid tulemuste otsimiseks ja fassaadide arvestamiseks, nagu Solr, ElasticSearch, Sphinx ja teised. K\u00f5ik need on loodud \"fassaadide\" loomiseks ja teevad seda piisavalt t\u00f5husalt, kasutades p\u00f6\u00f6ratud indekseerimist. Kuidas otsingumootorid t\u00f6\u00f6tavad, miks nad nendes olukordades on t\u00f5husamad kui tavalised andmebaasid, millised on praktika ja takistused \u2014 see on eraldi artikli teema. Kuid soovin t\u00e4helepanu juhtida sellele, et otsingumootor ei saa olla peamise andmehoidla asendaja; see on lisa: k\u00f5ik muudatused peamises andmebaasis, mis on otsingu jaoks olulised, s\u00fcnkroniseeritakse otsinguindeksisse; otsingumehhanism suhtleb tavaliselt ainult otsingumootoriga ega p\u00f6\u00f6rdu peamise andmebaasi poole. \u00dcks olulisemaid aspekte on see, kuidas korraldada s\u00fcnkroniseerimist usaldusv\u00e4\u00e4rselt. K\u00f5ik s\u00f5ltub \"reaktsiooniaja\" n\u00f5uetest. Kui aeg peamise andmebaasi muutmise ja selle \"kuvamise\" vahel otsingus ei ole kriitiline, saab luua teenuse, mis vaatab iga paari minuti tagant hiljaaegu muudetud kirjeid ja indekseerib need. Kui n\u00f5utav on v\u00f5imalikult minimaalne reaktsiooniaeg, saab rakendada midagi taolist. <noindex><a rel=\"nofollow\" href=\"https:\/\/microservices.io\/patterns\/data\/transactional-outbox.html\">transactional outbox<\/a><\/noindex> uuenduste saatmiseks otsinguteenusesse.<\/li>\n<\/ul>\n<p><\/p>\n<h2>J\u00e4reldused<\/h2>\n<p><\/p>\n<ol>\n<li>Server-side paging implementation is a serious complication, and it should only be applied for rapidly growing or simply large datasets. There is no absolutely precise recipe for evaluating what constitutes 'large' or 'rapidly growing,' but I would adhere to the following approach:\n<ul>\n<li>If obtaining the complete dataset, considering server time and data transfer, fits within performance requirements, then there is no point in implementing server-side paging.<\/li>\n<li>It may happen that there are currently no performance issues due to having little data, but the data collection is constantly growing. If a dataset might eventually no longer satisfy the previous point, it's better to lay the groundwork for paging right away.<\/li>\n<\/ul>\n<\/li>\n<li>If there is no strict business requirement for showing the total number of results or displaying page numbers, and your system does not have a search engine, it is better not to implement these aspects and instead consider option #2.<\/li>\n<li>If there is a clear requirement for faceted search, you have two options to avoid sacrificing performance:\n<ul>\n<li>Do not recalculate all counts with every change in search criteria.<\/li>\n<li>Use search engines such as Solr, ElasticSearch, Sphinx, and others. However, it should be understood that it cannot replace the main database and should be used as a complement to the primary storage to solve search tasks. <\/li>\n<\/ul>\n<\/li>\n<li>Also, in the case of faceted search, it makes sense to separate the retrieval of the search results page and the count of quantities into two parallel requests. The count of quantities may take longer than retrieving the results, while the results are more important for the user.<\/li>\n<li>If you are using an SQL database for searching, any code changes related to this part must be thoroughly tested for performance against the relevant volume of data (exceeding the volume in the 'live' database). It is also advisable to monitor query execution times on all database instances, especially on the 'live' one. Even if everything was fine during the development phase with the query plans, the situation may change significantly as the volume of data grows.<\/li>\n<\/ol>\n<p>Allikas: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/epam_systems\/blog\/493438\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041e\u0434\u0438\u043d \u0438\u0437 \u0442\u0438\u043f\u043e\u0432\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432 \u0432\u043e \u0432\u0441\u0435\u0445 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u0445 \u043d\u0430\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u2014 \u043f\u043e\u0438\u0441\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u044f\u043c \u0438 \u0432\u044b\u0432\u043e\u0434 \u0438\u0445 \u0432 \u0443\u0434\u043e\u0431\u043d\u043e\u043c \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0432\u0438\u0434\u0435. \u0422\u0443\u0442 \u0436\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u043e \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0435, \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0435, \u043f\u043e\u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043d\u043e\u043c\u0443 \u0432\u044b\u0432\u043e\u0434\u0443. \u0417\u0430\u0434\u0430\u0447\u0430, \u043f\u043e \u0438\u0434\u0435\u0435, \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u0430\u044f, \u043d\u043e \u043f\u0440\u0438 \u0435\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0438 \u043c\u043d\u043e\u0433\u0438\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0434\u0435\u043b\u0430\u044e\u0442 \u0440\u044f\u0434 \u043e\u0448\u0438\u0431\u043e\u043a, \u0438\u0437-\u0437\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u043e\u0442\u043e\u043c \u0441\u0442\u0440\u0430\u0434\u0430\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":75531,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-75530","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041e\u0434\u0438\u043d \u0438\u0437 \u0442\u0438\u043f\u043e\u0432\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432 \u0432\u043e \u0432\u0441\u0435\u0445 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u0445 \u043d\u0430\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u2014 \u043f\u043e\u0438\u0441\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u044f\u043c \u0438 \u0432\u044b\u0432\u043e\u0434 \u0438\u0445 \u0432 \u0443\u0434\u043e\u0431\u043d\u043e\u043c \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0432\u0438\u0434\u0435.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/vyvod-rezultatov-poiska-i-problemy-s-proizvoditelnostyu\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"et_EE\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0412\u044b\u0432\u043e\u0434 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0441 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041e\u0434\u0438\u043d \u0438\u0437 \u0442\u0438\u043f\u043e\u0432\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432 \u0432\u043e \u0432\u0441\u0435\u0445 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u0445 \u043d\u0430\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u2014 \u043f\u043e\u0438\u0441\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u044f\u043c \u0438 \u0432\u044b\u0432\u043e\u0434 \u0438\u0445 \u0432 \u0443\u0434\u043e\u0431\u043d\u043e\u043c \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0432\u0438\u0434\u0435.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/vyvod-rezultatov-poiska-i-problemy-s-proizvoditelnostyu\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-03-26T17:42:23+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-03-26T17:42:23+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Otsingutulemuste kuvamine ja t\u00f5hususe probleemid | ProHoster","description":"\u00dcks t\u00fc\u00fcpilisi stsenaariume k\u00f5ikides meie tuttavates rakendustes on andmete otsimine teatud kriteeriumide alusel ja nende kuvamine loetaval kujul.","canonical_url":"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/vyvod-rezultatov-poiska-i-problemy-s-proizvoditelnostyu","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"et_EE","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0412\u044b\u0432\u043e\u0434 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0441 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e | ProHoster","og:description":"\u041e\u0434\u0438\u043d \u0438\u0437 \u0442\u0438\u043f\u043e\u0432\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432 \u0432\u043e \u0432\u0441\u0435\u0445 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u0445 \u043d\u0430\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u2014 \u043f\u043e\u0438\u0441\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u044f\u043c \u0438 \u0432\u044b\u0432\u043e\u0434 \u0438\u0445 \u0432 \u0443\u0434\u043e\u0431\u043d\u043e\u043c \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0432\u0438\u0434\u0435.","og:url":"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/vyvod-rezultatov-poiska-i-problemy-s-proizvoditelnostyu","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-03-26T17:42:23+00:00","article:modified_time":"2020-03-26T17:42:23+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"75530","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 17:55:26","updated":"2022-10-02 02:12:16","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts\/75530","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/comments?post=75530"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts\/75530\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/media\/75531"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/media?parent=75530"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/categories?post=75530"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/tags?post=75530"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}