I am working on a huge dataset and I have a lot of data formatted in XML, we are talking about a couple of GBs. For this reason I am currently using the stream function to read them and extract the information I need. My goal is to join two datasets with a Mathematica function similar to Vlookup. The first record from the stream looks like this
<row Id="1" PostId="1" Answer="2" CreationDate="2015-10-29T15:56:52.933" Score="13" ViewCount="200" UserId="23" LastEditorUserId="729" LastEditDate="2016-09-27T17:44:28.253" LastActivityDate="2016-09-27T17:44:28.253" Skills="<.net><asp.net-web-api><asp.net>" AnswerCount="1" CommentCount="2" FavoriteCount="1" />
And the second like this
<row Id="2" Level="3345" CreationDate="2008-07-31T14:22:31.287" LastAccessDate="2018-03-10T01:20:14.367" Location="Corvallis, OR" Views="23041" Votes="646" Age="41" Sex="1" AccountId="2" />
Now what I would do is to create a list with the following elements: {"Id", "PostId", "CreationDate", "Score", "ViewCount", "UserId", "Skills", "Location"} and join the records where "UserId" and "AccountId" are equal. (i.e. one record has UserId=2 should be matched with the other which has AccountId=2)
My approach to this problem was:
- First screen in the records
- Save the minimum what I need
- Do the same for the other record
- Work on the Vlookup
However, my problems are relatively 2:
- I am new to Mathematica and I am not able to do a Vlookup
- I have something like 10 millions records, so efficiency is the priority
The code I used so far are the following.
SetStreamPosition[str, 0];
list = Flatten[
StringCases[{___ ~~ "Id=\"" ~~ ___, "CreationDate=\"" ~~ ___,
"Score=\"" ~~ ___, "ViewCount=\"" ~~ ___, "Skills=\"" ~~ ___}] /@
StringSplit[
Rest[ReadList[str, Record, RecordLists -> False,
WordSeparators -> {"\t", " "}]]] , 2];
pos = Flatten[Position[StringTake[#, 1 ;; 3] & /@ list, "Id="]];
AppendTo[pos, Length[list] + 1];
data = MapAt[DateObject, data, {All, "CreationDate"}];
data = Map[Association[Rule @@@ StringSplit[#, "="]] &,
Internal`PartitionRagged[list, Differences[pos]]];
newdata =
data[[All, {"Id", "PostId", "CreationDate", "Score",
"ViewCount", "UserId", "Skills"}]];
newdata =
MapAt[If[! MissingQ[#],
StringReplace[#, {"<" -> "<", ">" -> ">"}], #] &,
newdata, {All, "Skills"}]
]
and on the same style:
SetStreamPosition[str, 0];
list = Flatten[
StringCases[{___ ~~ "Id=\"" ~~ ___, "Location=\"" ~~ ___}] /@
StringSplit[
Rest[ReadList[str, Record, RecordLists -> False,
WordSeparators -> {"\t", " "}]]] , 2];
pos = Flatten[Position[StringTake[#, 1 ;; 3] & /@ list, "Id="]];
AppendTo[pos, Length[list] + 1];
data = Map[Association[Rule @@@ StringSplit[#, "="]] &,
Internal`PartitionRagged[list, Differences[pos]]];
newdata =
data[[All, {"AccountId", "Location"}]]
The last code is not perfect since it doesn't actually give the Location because it separated by comma it gives some problems.
My request for the Mathematica Stack Exchange world would be to help me figure out where actually the lines that are slowing down (and also why) and have a suggestion on how people more expert then me would achieve the goal of joining two datasets so big and with the following elements: {"Id", "PostId", "CreationDate", "Score", "ViewCount", "UserId", "Skills", "Location"}. Thanks in advance for your help and your time!