2017-07-26

nosql world


vasi radulescu

"Am consultat ieri o splendoare de doamnă. Avea 67 de ani și arăta de vreo 45. Cum partea pur medicală se limita la un colesterol mai măricel, am avut timp să discutăm despre literatură, călătorii, filme, prietenii, feluri de mâncare. O priveam și automat mă gândeam la mulți alți pacienți care mai niciodată nu au făcut nimic pentru ei, stând în situații apăsătoare, trăgând pentru alții, strângând pentru zile viitoare așa-zise negre, muncind pe brânci pierzându-și echilibrul psihic, iar apoi, în mod galopant, toate celelalte dându-se peste cap.
Pentru ce strângem bani și lucruri materiale? Pentru ce tot tragem ca să-i mulțumim pe cei din jurul nostru? Intrăm în zone cu nisipuri mișcătoare și nu ne dăm seama cum ne stricăm ca oameni, cum ne scufundăm și, într-un final, pare că am atins un calm, dar este doar nisipul care ne trece de nas și ne servește calmul final.
Trebuie să trăim în special pentru noi. Nu e egoism absurd și rece, e necesitate. Numai iubindu-ne, descoperindu-ne, cultivându-ne putem viețui frumos, apoi, ori de câte ori putem, vom face bine și celor de lângă noi. Viața e un cadou minunat și trebuie să ne bucurăm de el. E al nostru și, cu datele actuale, e irepetabil. La ce bun goane aiurea care ne distrug în loc să ne împlinească?
Doamna mea pacientă îmi povestea despre vizita pe Coasta Amalfi, ultimele cărți citite, renunțarea la cablu tv (îl ține pe domnul televizor numai pentru niște seriale pe Netflix), socializarea cu prietenii, poveștile spuse la un pahar de vin roșu, implicarea încă în niște proiecte interesante (unele pro bono, ajuta niște asociații și asta îi dădea o stare aparte), multiplele călătorii prin Grecia. Am terminat „consultația” și i-am zis că abia aștept să ne revedem.
Trăiți mai ales pentru voi, atingând niveluri care vă permit să faceți bine și-n jurul vostru. Bucurați-vă de lucrurile aparent mărunte care se întâmplă peste tot. Călătoriți. Țineți-vă ocupați cu proiecte frumoase. Nu vă sufocați în obiecte multe care nu vă ajută cu nimic. Nu vă pierdeți sănătatea în maratoane absurde pentru acumulări la fel de absurde.
Viața este, în primul rând, a voastră."

2017-07-05

parquet and hadoop

I think the main difference I can describe relates to record oriented vs. column oriented formats. Record oriented formats are what we're all used to -- text files, delimited formats like CSV, TSV. AVRO is slightly cooler than those because it can change schema over time, e.g. adding or removing columns from a record. Other tricks of various formats (especially including compression) involve whether a format can be split -- that is, can you read a block of records from anywhere in the dataset and still know it's schema? But here's more detail on columnar formats like Parquet.
Parquet, and other columnar formats handle a common Hadoop situation very efficiently. It is common to have tables (datasets) having many more columns than you would expect in a well-designed relational database -- a hundred or two hundred columns is not unusual. This is so because we often use Hadoop as a place to denormalize data from relational formats -- yes, you get lots of repeated values and many tables all flattened into a single one. But it becomes much easier to query since all the joins are worked out. There are other advantages such as retaining state-in-time data. So anyway it's common to have a boatload of columns in a table.
Let's say there are 132 columns, and some of them are really long text fields, each different column one following the other and use up maybe 10K per record.
While querying these tables is easy with SQL standpoint, it's common that you'll want to get some range of records based on only a few of those hundred-plus columns. For example, you might want all of the records in February and March for customers with sales > $500.
To do this in a row format the query would need to scan every record of the dataset. Read the first row, parse the record into fields (columns) and get the date and sales columns, include it in your result if it satisfies the condition. Repeat. If you have 10 years (120 months) of history, you're reading every single record just to find 2 of those months. Of course this is a great opportunity to use a partition on year and month, but even so, you're reading and parsing 10K of each record/row for those two months just to find whether the customer's sales are > $500.
In a columnar format, each column (field) of a record is stored with others of its kind, spread all over many different blocks on the disk -- columns for year together, columns for month together, columns for customer employee handbook (or other long text), and all the others that make those records so huge all in their own separate place on the disk, and of course columns for sales together. Well heck, date and months are numbers, and so are sales -- they are just a few bytes. Wouldn't it be great if we only had to read a few bytes for each record to determine which records matched our query? Columnar storage to the rescue!
Even without partitions, scanning the small fields needed to satisfy our query is super-fast -- they are all in order by record, and all the same size, so the disk seeks over much less data checking for included records. No need to read through that employee handbook and other long text fields -- just ignore them. So, by grouping columns with each other, instead of rows, you can almost always scan less data. Win!
But wait, it gets better. If your query only needed to know those values and a few more (let's say 10 of the 132 columns) and didn't care about that employee handbook column, once it had picked the right records to return, it would now only have to go back to the 10 columns it needed to render the results, ignoring the other 122 of the 132 in our dataset. Again, we skip a lot of reading.
(Note: for this reason, columnar formats are a lousy choice when doing straight transformations, for example, if you're joining all of two tables into one big(ger) result set that you're saving as a new table, the sources are going to get scanned completely anyway, so there's not a lot of benefit in read performance, and because columnar formats need to remember more about the where stuff is, they use more memory than a similar row format).
One more benefit of columnar: data is spread around. To get a single record, you can have 132 workers each read (and write) data from/to 132 different places on 132 blocks of data. Yay for parallelization!
And now for the clincher: compression algorithms work much better when it can find repeating patterns. You could compress AABBBBBBCCCCCCCCCCCCCCCC as 2A6B16C but ABCABCBCBCBCCCCCCCCCCCCCC wouldn't get as small (well, actually, in this case it would, but trust me :-) ). So once again, less reading. And writing too.
So we read a lot less data to answer common queries, it's potentially faster to read and write in parallel, and compression tends to work much better.
Columnar is great when your input side is large, and your output is a filtered subset: from big to little is great. Not as beneficial when the input and outputs are about the same.
But in our case, Impala took our old Hive queries that ran in 5, 10, 20 or 30 minutes, and finished most in a few seconds or a minute.
Hope this helps answer at least part of your question!