<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Gabriele Lana &#187; erlang</title>
	<atom:link href="http://www.gabrielelana.it/archives/category/erlang/feed" rel="self" type="application/rss+xml" />
	<link>http://www.gabrielelana.it</link>
	<description>on Agile Methodologies and Programming</description>
	<lastBuildDate>Fri, 07 May 2010 14:12:28 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>CouchDB Performance</title>
		<link>http://www.gabrielelana.it/archives/131</link>
		<comments>http://www.gabrielelana.it/archives/131#comments</comments>
		<pubDate>Sun, 11 Oct 2009 09:36:43 +0000</pubDate>
		<dc:creator>Gabriele Lana</dc:creator>
				<category><![CDATA[couchdb]]></category>
		<category><![CDATA[erlang]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.gabrielelana.it/?p=131</guid>
		<description><![CDATA[Finalmente sono riuscito a provare CouchDB con una quantità di dati interessante e su una macchina interessante. L&#8217;obiettivo era quello di verificare se CouchDB poteva reggere un carico di milioni di documenti e se il tempo per il calcolo delle view è effettivamente incrementale e con complessità logaritmica.
Una brevissima introduzione: CouchDB è un database documentale, [...]]]></description>
			<content:encoded><![CDATA[<p>Finalmente sono riuscito a provare <a href="http://couchdb.apache.org/">CouchDB</a> con una quantità di dati interessante e su una macchina interessante. L&#8217;obiettivo era quello di verificare se CouchDB poteva reggere un carico di milioni di documenti e se il tempo per il calcolo delle view è effettivamente incrementale e con complessità logaritmica.</p>
<p>Una brevissima introduzione: CouchDB è un database documentale, ogni documento (il record di una tabella in un database relazionale) è insieme di coppie chiave/valore, non esiste uno schema dei dati, ogni documento può contenere qualsiasi insieme di coppie chiave/valore, ad ogni database possono essere associati una o più view (query in un database relazione), ogni view è composta da due funzioni javascript, una funzione <em>map</em> che consente di trasformare ogni documento contenuto nel database in un altro insieme di coppie chiave/valore e di associarle ad una chiave, e una funzione <em>reduce</em> (opzionale) che prende in pasto l&#8217;output della funzione map precedente raggruppata per chiave (una sorta di <em>group by</em> dei database relazionali) e che può essere utilizzata per computare valori aggregati</p>
<p>Un piccolissimo esempio che è molto vicino al test che ho fatto. Supponiamo di avere un database (ovvero un insieme di documenti) di questo tipo</p>
<blockquote><p>
[<br />
  {<br />
    "url": "http://salute.corriere.it/news/some-news.html",<br />
    "visits": 3<br />
  },<br />
  {<br />
    "url": "http://lavoro.corriere.it/index.html",<br />
    "visits": 10<br />
  }<br />
]
</p></blockquote>
<p>Ovvero associamo ad ogni url il numero di volte che è stata visitata. Noi vogliamo sapere il numero di visite per ogni <em>&#8220;sezione&#8221;</em> delle url presenti nel nostro database. Definiamo intuitivamente il significato di <em>&#8220;sezione&#8221;</em> dicendo che l&#8217;url <em>&#8220;http://salute.corriere.it/news/some-news.html&#8221;</em> appartiene a tre sezioni <em>&#8220;corriere.it&#8221;</em>, <em>&#8220;salute.corriere.it&#8221;</em> e <em>&#8220;salute.corriere.it/news&#8221;</em>. Supponiamo di avere a disposizione una funzione <em>&#8220;forEachSectionOf(url,doSomething)&#8221;</em> che prede in pasto una <em>url</em> e richiama la funzione <em>doSomething</em> per ogni sezione dell&#8217;url passandogli la sezione stessa come parametro. La nostra funzione map sarebbe una cosa del tipo</p>
<blockquote><p>
function(doc) {<br />
  forEachSectionOf(doc['url'], function(section) {<br />
    emit(section, doc['visits'])<br />
  });<br />
}
</p></blockquote>
<p>La funzione <em>emit</em> viene chiamata tutte le volte che vi vuole produrre un output, il primo parametro è la chiave del risultato e il secondo è il valore (sia la chiave che il valore possono essere strutture dati complesse, non devono essere per forza valori come in questo caso, ma questa è un&#8217;altra storia). L&#8217;output prodotto dalla <em>map</em> applicata al database di cui sopra sarà</p>
<blockquote><p>
[<br />
  { "corriere.it": 3 },<br />
  { "salute.corriere.it": 3 },<br />
  { "salute.corriere.it/news": 3 },<br />
  { "corriere.it": 10 },<br />
  { "lavoro.corriere.it": 10 }<br />
]
</p></blockquote>
<p>Abbiamo detto che l&#8217;imput alla <em>reduce</em> è l&#8217;output della <em>map</em> raggruppato per chiave, quindi</p>
<blockquote><p>
[<br />
  { "corriere.it": [ 3, 10 ] },<br />
  { &#8220;salute.corriere.it&#8221;: [ 3 ] },<br />
  { &#8220;salute.corriere.it/news&#8221;: [ 3 ] },<br />
  { &#8220;lavoro.corriere.it&#8221;: [ 10 ] }<br />
]
</p></blockquote>
<p>Ricordandoci che vogliamo calcolare il numero di visite per ogni sezione, la reduce è molto semplice</p>
<blockquote><p>
function(keys, values, rereduce) {<br />
  return sum(values)<br />
}
</p></blockquote>
<p>Che produce il risultato atteso</p>
<blockquote><p>
[<br />
  { "corriere.it": 13 },<br />
  { "salute.corriere.it": 3 },<br />
  { "salute.corriere.it/news": 3 },<br />
  { "lavoro.corriere.it": 10 }<br />
]
</p></blockquote>
<p>Il grosso vantaggio di CouchDB in termini di perfomance è che le view vengono calcolate in maniera incrementale, ovvero tutte le volte che interroghi una view CouchDB ricalcola solo i valori relativi ai documenti che sono cambiati o che sono stati aggiunti dall&#8217;ultima volta che la stessa view era stata calcolata (la cosa più vicina a questa nel mondo dei database relazionali sono le <a href="http://download.oracle.com/docs/cd/B10500_01/server.920/a96567/repmview.htm">materialized view</a> di Oracle). Inoltre il costo del calcolo dell&#8217;incremento dovrebbe aumentare in maniera logaritmica rispetto all&#8217;aumentare della dimensione del database.</p>
<p>Ho voluto toccare con mano e quindi ho fatto il seguente esperimento:</p>
<ul>
<li>Fetch di 10000 record da una tabella di mysql contenente 15 milioni di record</li>
<li>Store di ogni record come documento in CouchDB (i documenti non sono stati salvati singolarmente, ma in modalità batch che è molto più performante)</li>
<li>Query della view di CouchDB che equivale al ricalcolo della view stessa</li>
</ul>
<p>Ho misurato ognuna delle tre fasi e l&#8217;ho ripetuto fino a consumare tutti e 15 i milioni di record, di seguito i risultati</p>
<p><a href="http://www.gabrielelana.it/wp-content/uploads/2009/10/urls_per_domain.times.gif"><img src="http://www.gabrielelana.it/wp-content/uploads/2009/10/urls_per_domain.times-300x225.gif" alt="urls_per_domain.times" title="urls_per_domain.times" width="300" height="225" class="aligncenter"/></a></p>
<ul>
<li>Pro: la complessità del ricalcolo della view è effettivamente logaritmico</li>
<li>Pro: il costo d&#8217;inserimento dei documenti in CouchDB è costante (la struttura dati utilizzata è append-only, quindi c&#8217;era da aspettarselo, ma fa comunque piacere verificarlo)</li>
<li>Pro: una volta calcolata la view, i tempi di risposta sono stupefacenti, praticamente istantanei</li>
<li>Pro: il tempo totale d&#8217;inserimento di 15 milioni di documenti è stato di 26 minuti</li>
<li>Pro: l&#8217;occupazione di memoria durante tutto il processo non ha mai superato i 50MB</li>
<li>Contro: il tempo totale di calcolo della view è stato di circa 17 ore. Bisogna tener conto che le view vengono calcolate da funzioni javascript in un processo separato e che la comunicazione fra CouchDB e l&#8217;interprete javascript è stdin/stdout, quindi a parte la velocità dell&#8217;interprete javascript (di default spidermonkey) c&#8217;è anche un costo notevole di serializzazione/deserializzazione. Scommetto che scrivendo le map/reduce direttamente in Erlang questo numero cambierebbe sensibilmente
<li>Contro: lo spazio occupato dal database è di 21GB contro i 7.5GB di mysql (anche se ci metterei un bel chissene visto il costo degli storage)</li>
<li>Contro: lo spazio occupato dalla view è di 32GB (again chissene)</li>
<li>Contro: per ogni database CouchDB usa uno ed un solo processore, quindi anche se avete 16 processori come nel mio caso, non ve ne fate niente a meno di non avere database multipli. Il modello map/reduce implementato da CouchDB potrebbe tranquillamente consentire il partizionamento dei dati su più database, ma attualmente gli sviluppatori si stanno concentrando solamente sulla replicazione, se volete dovete implementare voi il meccanismo di reduce finale</li>
</ul>
<p>Conclusione: se vi trovate in una situazione per cui avete una grande quantità di dati e le query che fate non cambiano spesso, un database come CouchDB potrebbe essere un bel passo in avanti rispetto ad un database tradizionale</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gabrielelana.it/archives/131/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Bowling kata in Erlang</title>
		<link>http://www.gabrielelana.it/archives/102</link>
		<comments>http://www.gabrielelana.it/archives/102#comments</comments>
		<pubDate>Fri, 24 Jul 2009 14:10:54 +0000</pubDate>
		<dc:creator>Gabriele Lana</dc:creator>
				<category><![CDATA[erlang]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[test]]></category>

		<guid isPermaLink="false">http://www.gabrielelana.it/archives/102</guid>
		<description><![CDATA[Qualche giorno fa Robert Martin come esercizio per imparare Clojure ha risolto il kata del bowling (da lui stesso ideato). Qualche programmatore più avvezzo al mondo funzionale ha cassato la soluzione ritenendola troppo &#8220;imperativa&#8221;, accusando non tanto Martin stesso quanto la presenza dei test :-D
L&#8217;argomentazione utilizzata per minimizzare l&#8217;utilità dei test è la semplicità dell&#8217;esercizio, [...]]]></description>
			<content:encoded><![CDATA[<p>Qualche giorno fa <a href="http://objectmentor.com/omTeam/martin_r.html">Robert Martin</a> come esercizio per imparare <a href="http://clojure.org/">Clojure</a> ha <a href="http://blog.objectmentor.com/articles/2009/07/19/uncle-bob-jsps-learning-clojure">risolto</a> il <a href="http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata">kata del bowling</a> (da lui stesso ideato). Qualche programmatore più avvezzo al mondo funzionale ha cassato la soluzione ritenendola troppo &#8220;imperativa&#8221;, accusando non tanto Martin stesso quanto la presenza dei test :-D</p>
<p>L&#8217;argomentazione utilizzata per minimizzare l&#8217;utilità dei test è la semplicità dell&#8217;esercizio, al che ho pensato a come l&#8217;avrei risolto in <a href="http://erlang.org/">Erlang</a>, mi sono detto che &#8220;effettivamente la soluzione è semplice&#8221;, ho iniziato a scriverla provandola nella shell del linguaggio e subito ho provato un senso di fastidio</p>
<p>Continuavo a scrivere e riscrivere (va bhe, la shell ti da la possibilità di richiamare i comandi passati, ma il discorso non cambia) le stesse invocazioni verificando ad occhio il risultato, al che ho capito il senso di fastidio: che differenza c&#8217;è fra quello che stavo facendo e scrivere dei test unitari? Nessuna, tranne che i primi sono effimeri e non ti possono venire in aiuto quando sarai chiamato a fare refactoring. Quindi, amici dei linguaggi funzionali, perchè non vedete i test unitari come delle sessioni di interazione con la shell permanenti e automatiche?</p>
<p>Vi dirò di più, la soluzione che avevo inizialmente pensato era sbagliata :-) Dopo aver passato tutti i test che Martin aveva fatto nella presentazione di cui sopra, mi sono chiesto se potevo rompere il codice in qualche modo, ho visto che non erano coperti dei corner case, per esempio c&#8217;è la partita peggiore (tutti 0), ma non c&#8217;è la partita migliore (tutti strike), scrivo un test&#8230; e non passa :-)</p>
<p>Come vedete qui sotto, utilizzo una variabile per tenere il conto dei frame elaborati, inizialmente non lo facevo e nel caso di uno strike nell&#8217;ultimo frame, i due tiri di bonus successivi metchavano con la terza clausola e venivano considerati dei frame normali, quindi il &#8220;perfect game&#8221; che dovrebbe avere uno score di 300 aveva score 320</p>
<p><script src="http://gist.github.com/154187.js"></script></p>
<p>Alla fine ho guardato il codice e quella variabile arbitraria per contare il numero dei frame proprio non mi andava giù e senza cambiare i test sono arrivato a questa seconda soluzione</p>
<p><script src="http://gist.github.com/154189.js"></script></p>
<p>Che non mi piace perchè anche se rende più esplicito (forse anche più imperativo?) il conto dei frame, secondo me si capisce di meno, sopratutto non mi piace <strong>score_frame</strong> perchè si occupa sia di calcolare lo score di un frame (e fin qui), sia di selezionare i tiri rimanenti eliminando quelli del frame corrente</p>
<p>Cosa ne dite? Quale vi piace di più?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gabrielelana.it/archives/102/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Introduction to Erlang @ milano-xpug</title>
		<link>http://www.gabrielelana.it/archives/95</link>
		<comments>http://www.gabrielelana.it/archives/95#comments</comments>
		<pubDate>Sat, 28 Feb 2009 11:04:58 +0000</pubDate>
		<dc:creator>Gabriele Lana</dc:creator>
				<category><![CDATA[erlang]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.gabrielelana.it/archives/95</guid>
		<description><![CDATA[
View more presentations from gabriele.lana. (tags: erlang introduction)

Mi piacerebbe raccontare di più su questo fantastico linguaggio/ambiente, è che mi manca proprio il tempo&#8230;
]]></description>
			<content:encoded><![CDATA[<div style="width:425px;text-align:center;margin:0 auto" id="__ss_1082526"><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slideshare.net/swf/ssplayer2.swf?doc=20092502erlangmilano-xpug-090228045848-phpapp01&#038;stripped_title=20092502erlangmilano-xpug" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slideshare.net/swf/ssplayer2.swf?doc=20092502erlangmilano-xpug-090228045848-phpapp01&#038;stripped_title=20092502erlangmilano-xpug" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/gabriele.lana">gabriele.lana</a>. (tags: <a style="text-decoration:underline;" href="http://slideshare.net/tag/erlang">erlang</a> <a style="text-decoration:underline;" href="http://slideshare.net/tag/introduction">introduction</a>)</div>
</div>
<p>Mi piacerebbe raccontare di più su questo fantastico linguaggio/ambiente, è che mi manca proprio il tempo&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gabrielelana.it/archives/95/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
