[php]Text tussen twee strings vervangen door database waarde

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Vissie
  • Registratie: November 2002
  • Laatst online: 07-09 13:18

Vissie

...mine, mine, mine

Topicstarter
Zoals in de titel te lezen is, wil ik de tekst tussen twee strings vervangen door een waarde die uit mijn database wordt opgehaald en die wordt bepaald door de tekst tussen de twee strings. Om het een en ander te verduidelijken heb ik hier een voorbeeld.

Ik wil bijvoorbeeld [ i ]appel[ /i ] vervangen door een link naar de productpagina van appel. In mijn MySQL database gebruik ik deze opbouw:

productidproductnaamproducturl
1appelwww.appel.nl
2peerwww.peer.nl


Elke keer als de text geparsed wordt moet elke tekst tussen [ i ] en [ /i ] veranderd worden in een link naar het product, indien beschikbaar in de database.

Het probleem is niet het linken naar de database of het ophalen van de databasegegevens, dat krijg ik allemaal prima voor elkaar. Het probleem is het php gedeelte van het vinden en vervangen.

Het is niet mogelijk om alle producten en producturls van te voren op te halen en in een array te zetten, het gaat namelijk om meer dan 500.000 producten, dus dat komt de performance niet ten goede.

De string tussen [ i ] en [ /i ] moet dus opgehaald worden en aan de hand van die string moet met een select query de juiste database entry worden opgezocht.

Ik ben hier nu al dagen mee bezig, maar kan geen werkende oplossing vinden. Ik heb pogingen gedaan met diverse split en replace van PHP, maar dat mocht niet baten. Mijn oplossingen worden inmiddels zo complex dat ik een eventuele eenvoudige oplossing niet meer zie. Ik ben heel benieuwd of iemand mij hier mee kan helpen! :)

[ Voor 8% gewijzigd door Vissie op 12-10-2009 12:15 . Reden: de tags waren niet zichtbaar ]


Acties:
  • 0 Henk 'm!

  • jbdeiman
  • Registratie: September 2008
  • Laatst online: 07:08
@Vissie
Een beetje een heel rare manier van als ik eerlijk ben:
Je hebt meer dan 500.000 producten geef je aan, hoeveel tekst staat er op de website en hoeveel woorden moeten er doorlopen worden voor de linkjes?

Ik neem aan dat dat behoorlijk veel is en dat is niet handig.

Eigenlijk zijn er zo 2 opties:
zoek/ vervang vanuit de producten in de database
zoek/ vervang vanuit de woorden in je tekst.

Beide opties zijn eigenlijk geen goede opties voor wat betreft de zwaarte van de code.

Acties:
  • 0 Henk 'm!

  • Vissie
  • Registratie: November 2002
  • Laatst online: 07-09 13:18

Vissie

...mine, mine, mine

Topicstarter
Thanks voor je reply.

Ik zorg er express voor dat alle verwijzingen in de teksten die doorzocht moeten worden omgeven worden door en om een zeer zware load te voorkomen. Ik wil de opgeslagen teksten in de database echter niet actief wijzigen, ik wil ze slechts parsen. De teksten moeten later namelijk ook nog bewerkt kunnen worden.

Het moet toch mogelijk zijn om de strings tussen [ i ] en [ /i ] te isoleren, op te slaan in een variabele en aan de hand daarvan een resultaat uit de database te trekken, om vervolgens de originele string tussen [ i ] en [ /i ] daarmee te vervangen?

Dit lijkt mij qua performance de juiste oplossing, en bij deze oplossing maakt het ook niet zo gek veel uit hoeveel producten er in de database staan. Heb jij nog een alternatieve oplossing, die niet leidt tot teveel performance verlies?

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Je bedoelt dat de te vervangen woorden tussen [i] en [\i] staan? Dat is nu nogal onduidelijk omdat GoT die tags ook parsed ;) Edit: ah dat had je ook al door ;)

Maar een eenvoudige optie zou zijn om gewoon een stack-based parser te maken/gebruiken en dan als je de content van een [i] tag moet verwerken gewoon een select op de database doen. Met een klein aantal [i] elementen per text zal dit geen enorme load opleveren.

Als dit veel load oplevert zou je kunnen denken om ook de resulterende text op te slaan, en deze elke keer te wijzigen als de bron-text veranderd.

[ Voor 10% gewijzigd door Woy op 12-10-2009 12:17 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

jbdeiman schreef op maandag 12 oktober 2009 @ 12:06:
Je hebt meer dan 500.000 producten geef je aan, hoeveel tekst staat er op de website en hoeveel woorden moeten er doorlopen worden voor de linkjes?
En, hoe vaak moet een dergelijke tekst omgezet worden, en hoeveel matches denk je gemiddeld te hebben met een stuk tekst?

Maar op het eerste gezicht zou ik de tekst opdelen in woorden, dubbelen en stopwoorden eruit filteren, en dan een SELECT ... WHERE woord IN (<woordenlijst>) doen om de relevante data op te halen.
Vissie schreef op maandag 12 oktober 2009 @ 12:13:
Thanks voor je reply.

Ik zorg er express voor dat alle verwijzingen in de teksten die doorzocht moeten worden omgeven worden door en om een zeer zware load te voorkomen. Ik wil de opgeslagen teksten in de database echter niet actief wijzigen, ik wil ze slechts parsen. De teksten moeten later namelijk ook nog bewerkt kunnen worden.
Wil je hiermee aangeven dat het bij elke pageview moet gebeuren? Dat zou ik sowieso niet doen, en gewoon zowel het origineel als de gewijzigde tekst in de database opslaan.

[ Voor 35% gewijzigd door .oisyn op 12-10-2009 12:20 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Vissie
  • Registratie: November 2002
  • Laatst online: 07-09 13:18

Vissie

...mine, mine, mine

Topicstarter
Thx Woy,

Dit is waarschijnlijk een beter idee om mee aan de slag te gaan, dan het initiele idee dat ik had. De stack based parser is vrij eenvoudig te bouwen.

En tsja, dat GoT ook die tags ook post; d0h! ;)

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Vissie schreef op maandag 12 oktober 2009 @ 12:22:
Thx Woy,

Dit is waarschijnlijk een beter idee om mee aan de slag te gaan, dan het initiele idee dat ik had. De stack based parser is vrij eenvoudig te bouwen.
Maar zoals ik ( en .oisyn ) al zei: Ik zou het niet elke view parsen, maar alleen bij het wijzigen van de content doen. Daar bespaar je nog veel mee mee. Het kost wat extra ruimte in je database, maar is een stuk beter voor je performance. Je moet alleen zorgen dat de waardes synchroon blijven, en dus bij het wijzigen beide geupdate worden.
Vissie schreef op maandag 12 oktober 2009 @ 12:22:
En tsja, dat GoT ook die tags ook post; d0h! ;)
offtopic:
Dat kun je gewoon voorkomen door \[i] te typen ;)

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • flowerp
  • Registratie: September 2003
  • Laatst online: 11-09 18:20
[b][message=32724382,noline]
Ik wil bijvoorbeeld [ i ]appel[ /i ] vervangen door een link naar de productpagina van appel. In mijn MySQL database gebruik ik deze opbouw:
Je kunt dit denk ik het makkelijkst oplossen door gewone expression language statements in je view te gebruiken. Je producten modelleer je dan als entities met de naam als ID en de URL als attribute. Vervolgens gebruik je de second level cache van je persistence implementation (b.v. Hibernate) om de load op je DB nagenoeg geheel weg te nemen.

b.v.

XML:
1
Hoi dit is het #{rep['apple']} voorbeeld.


'rep' verwijst dan naar een managed bean, en binnen die bean doe je alleen iets als het volgende:

Java:
1
2
3
4
5
@PersistenceContext em;

public String get(String key) {
   return em.find(Replacement.class, key).url;
}


Die Replacement is dan een simpel ding als:

Java:
1
2
3
4
5
@Cache(usage = READ_WRITE)
@Entity public class Replacement {
   @Id String name;
   String url;
}


(deze mapped dus standaard naar een tabel 'replacement' met columns 'name' en 'url')

Als laatste stel je dan in je cache provider (b.v. Jboss Cache) in dat je een bepaald maximum aan items wilt cachen (b.v. 20.000) en geef je een LRU eviction policy op zodat bij het overschrijden van dit aantal de laatst gebruikte item gedelete wordt van de cache.

Je hoeft nu niets zelf te parsen en bij het aanpassen van de waardes in de DB (wel via de entity manager doen!) wordt de cache ook automatisch aangepast. Eigenlijk hoef je voor de oplossing van dit probleem amper zelf code te schrijven, maar kun je een aantal bestaande dingen die het framework je al biedt eenvoudig aan elkaar knopen.

It's shocking to find how many people do not believe they can learn, and how many more believe learning to be difficult.


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Hey kijk, een PHP topic ;)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Comgenie
  • Registratie: Oktober 2005
  • Laatst online: 12-09 13:09

Comgenie

Soms heb je dat

Voor het replacen van alles tussen tags met PHP naar verschillende teksten kan je de volgende php functie gebruiken:
http://nl3.php.net/manual...preg-replace-callback.php

Deze functie gebruikt regex en zou bij de 'gevonden resultaten' aan een functie (de callback) vragen waar het heen moet worden veranderd. Daar kan je dus de Database lookup code in zetten.

Regex zorgt echter ook voor veel load dus het is aan te raden dit alleen te doen bij wijzigingen, om het aanpasbaar te houden kan je de bron pagina in een ander veld/bestand/iets opslaan.

[ Voor 4% gewijzigd door Comgenie op 12-10-2009 15:04 ]

No animals were harmed in the making of this comment.


Acties:
  • 0 Henk 'm!

  • flowerp
  • Registratie: September 2003
  • Laatst online: 11-09 18:20
Verhip! 8)7

It's shocking to find how many people do not believe they can learn, and how many more believe learning to be difficult.


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Comgenie schreef op maandag 12 oktober 2009 @ 15:01:
Regex zorgt echter ook voor veel load dus [...]
Ik denk toch dat de load vooral zal komen van de database-lookups, en niet zozeer van die paar regexen die nog gecached kunnen worden ook... Het is even de vraag of je direct preg_replace_callback wil doen, evt met memcache oid, of dat je het met preg_match oplost. Misschien is preg_split wel een goede oplossing hier, met iets als #\\\[ i ](.*?)\\\[ /i ]# en PREG_SPLIT_DELIM_CAPTURE. Daarna alle oneven resultaten nemen (for($i=1;$i<..;$i+=2)), opzoeken (met IN), in geassocieerde array stoppen, alle oneven rijen vervangen, en de boel weer samenvoegen. Ontdubbelen doet de db-engine wel. :)

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • kaesve
  • Registratie: Maart 2009
  • Laatst online: 16-05 03:04
//oftopic: volgens mij is het belangerijkste doel van dit topic stiekem reclame maken voor Appèl en van Peer bv :+

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

pedorus schreef op maandag 12 oktober 2009 @ 19:49:
Ontdubbelen doet de db-engine wel. :)
Beetje suf, die data moet wel over het lijntje naar de db toe. En het is niet dat de db het sneller kan oid. Pleur gewoon alles in een array als key, waarna je uiteindelijk array_keys() gebruikt om de array met unieke elementen te krijgen.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
.oisyn schreef op maandag 12 oktober 2009 @ 21:58:
En het is niet dat de db het sneller kan oid.
Ligt eraan, als de db de data toch al sorteert, en de dubbelen er dan uitgooit kan de db het wel degelijk iets sneller. Maar het was vooral zo'n detail dat ik YAGNI, totdat het tegendeel is bewezen, dacht. :Y)

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Guess again. Sorteren is op z'n best O(n log n). Dubbelen filteren met een hashtable (wat PHP arrays zijn) is O(n)

[ Voor 10% gewijzigd door .oisyn op 12-10-2009 22:57 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Tsja, maar om hoeveel items gaat het eigenlijk? Het is natuurlijk niet zo dat O(nlog(n)) altijd sneller is dan O(n). :) Verder: Gaat de db eigenlijk wel sorteren? (Gezien de 500.000 op zeg max. 100 verhouding waarschijnlijk toch niet..) Waar is de meeste capaciteit over (db of php)? Is php of de db sneller hierin? Zijn dubbelen zeldzaam of niet? Enz. Er zijn te veel onbekende parameters om echt te weten wat het beste is, het verschil is waarschijnlijk niet merkbaar, en ik denk dat implementatietijd dan maar de doorslag moet geven. ;)

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • doeternietoe
  • Registratie: November 2004
  • Laatst online: 17-09 20:56
Comgenie schreef op maandag 12 oktober 2009 @ 15:01:
Voor het replacen van alles tussen tags met PHP naar verschillende teksten kan je de volgende php functie gebruiken:
http://nl3.php.net/manual...preg-replace-callback.php
Er komt bij mij het onderschrift van een bepaalde tweaker bovendrijven... :p

Nee, serieus, jouw methode is een mogelijk oplossing en een tamelijk goed ook, dat zal ik niet ontkennen. Toch zou ik zelf de stack-based parser prefereren, omdat die m.i. overzichtelijker is en zowieso waarschijnlijk performanter is.

Stack-based is hoe dan ook flexibeler en beter schaalbaar. Wat als er in de toekomst een andere tag bijkomt met een andere functie en ze moeten recursief worden toegepast? Dan wordt je regexp ineens een vreselijk stuk ingewikkelder. Je parser wordt dat ook, maar je behoudt veel beter het overzicht.

De TS moet zelf maar zien wat hij doet.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

pedorus schreef op maandag 12 oktober 2009 @ 23:18:
Tsja, maar om hoeveel items gaat het eigenlijk? Het is natuurlijk niet zo dat O(nlog(n)) altijd sneller is dan O(n).
Het gaat er natuurlijk om wanneer je daar überhaupt zorgen om gaat maken. Wanneer is dat? Nou, als n groot wordt. En laat bij een grote n het nou net zo zijn dat elementen in een hashtable zetten sneller is dan elementen sorteren.
Verder: Gaat de db eigenlijk wel sorteren? (Gezien de 500.000 op zeg max. 100 verhouding waarschijnlijk toch niet..)
Ik gok dat een db sowieso niet sorteert bij een WHERE IN() query eigenlijk, maar dat was jouw bewering ;)
Waar is de meeste capaciteit over (db of php)? Is php of de db sneller hierin? Zijn dubbelen zeldzaam of niet? Enz. Er zijn te veel onbekende parameters om echt te weten wat het beste is, het verschil is waarschijnlijk niet merkbaar
Allemaal fair points, maar ga dan niet eerst lopen roepen dat A sneller is dan B, en dan als reactie op een argument dat B sneller is zeggen dat de vergelijking niet gemaakt kan worden zonder context. :)

(Overigens, let erop dat mijn eerste reactie in de draad was gebaseerd op een topicstart waarin niet duidelijk stond dat alle om te zetten woorden tussen tags stonden omdat die tags werden geparsed door GoT's reactie-systeem, waardoor het leek alsof hij ieder woord in de gehele tekst door de db heen wilde halen. Ik ben het met je eens dat op het moment je alleen nog relevante woorden over hebt het niet meer uitmaakt)
doeternietoe schreef op maandag 12 oktober 2009 @ 23:40:
[...]

Er komt bij mij het onderschrift van een bepaalde tweaker bovendrijven... :p

Nee, serieus, jouw methode is een mogelijk oplossing en een tamelijk goed ook, dat zal ik niet ontkennen. Toch zou ik zelf de stack-based parser prefereren, omdat die m.i. overzichtelijker is en zowieso waarschijnlijk performanter is.
Euh, nee. Laat dit nou een typisch voorbeeld zijn van waar een regex juist goed uitkomt. En vertel me eens, hoe ga jij je stackbased-parser bouwen (naast het feit dat je stack in dit geval maar max 1 level diep is) zonder een regex die je string opdeelt in een tokenstream? Zelf met PHP code character voor character door de string heen lopen? En mocht je uiteindelijk naderhand een stackbased-parser nodig hebben, dan kun je je regex iets aanpassen en de parser gewoon toevoegen. Hij is op dit moment gewoon nog niet nodig, en het is tevens niet zo dat je code weg moet gooien op het moment dat je 'm wel nodig gaat hebben.

[ Voor 52% gewijzigd door .oisyn op 13-10-2009 00:28 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • doeternietoe
  • Registratie: November 2004
  • Laatst online: 17-09 20:56
.oisyn schreef op dinsdag 13 oktober 2009 @ 00:07:
Zelf met PHP code character voor character door de string heen lopen?
Min of meer :P Ik doe zelf vaak dat ik met strpos icm een loop door een string heenloop.

Je hebt natuurlijk gelijk dat er niets mis is met het gebruik van regexp in dit geval, dat zei ik al. Het is alleen zo dat ik zelf een (waarschijnlijk te grote) aversie heb tegen regexp omdat die snel onoverzichtelijk worden. Ik verlies het overzicht al als ik een expressie heb van meer dan vijf tekens lang :(
Pagina: 1