<?xml version="1.0" encoding="utf-8" standalone="yes"?><feed xmlns="http://www.w3.org/2005/Atom">
  <title></title>
  <subtitle></subtitle>
  <id>https://www.endpointdev.com/blog/tags/data-processing/</id>
  <link href="https://www.endpointdev.com/blog/tags/data-processing/"/>
  <link href="https://www.endpointdev.com/blog/tags/data-processing/" rel="self"/>
  <updated>2023-02-06T00:00:00+00:00</updated>
  <author>
    <name>End Point Dev</name>
  </author>
  
    <entry>
      <title>Find Text in Any Column of a PostgreSQL Table</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2023/02/find-text-in-any-column/"/>
      <id>https://www.endpointdev.com/blog/2023/02/find-text-in-any-column/</id>
      <published>2023-02-06T00:00:00+00:00</published>
      <author>
        <name>Josh Tolley</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2023/02/find-text-in-any-column/sunset-clouds-power-lines.webp&#34; alt=&#34;Three tiers of power lines lead from the left side of the image down towards a power pole directly in the bottom center. The pole sits just higher than trees lining the bottom of the image, haloed by a circular cloud, lit orange by the sunset, spreading to the edges of the image to fill it.&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Seth Jensen, 2022 --&gt;
&lt;p&gt;It&amp;rsquo;s not uncommon for me to want to find a particular text snippet in a
PostgreSQL database. Easy enough, you might say. After all, that&amp;rsquo;s what
databases are for: You feed them a bunch of information, ask them questions in
the form of a query, and they give you the answer. So just write a query,
right?&lt;/p&gt;
&lt;p&gt;Well, maybe.&lt;/p&gt;
&lt;p&gt;SQL stands for &amp;ldquo;Structured Query Language&amp;rdquo;, and the fact that it&amp;rsquo;s &amp;ldquo;structured&amp;rdquo;
means not only that the database abides by some defined structure, but that
your queries do, too, which implies that you know at the time you&amp;rsquo;re writing
the query where in the structure you want to look. And that&amp;rsquo;s where the problem
arises. What if I know &amp;ldquo;Kilroy&amp;rdquo; is somewhere in a table, but I don&amp;rsquo;t know
what column to look in to find him? How do I write &lt;em&gt;that&lt;/em&gt; query?&lt;/p&gt;
&lt;p&gt;The first answer I came up with to that question depends on &lt;code&gt;pg_dump&lt;/code&gt;: dump the
contents of a table, search the results with &lt;code&gt;grep&lt;/code&gt;, and there you have it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pg_dump -t person mydb | grep -i kilroy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;633132  F       NH      \N      Cristen212      J    Kilroy44        1983-09-28 00:00:00     \N      t       \N      \N      \N      \N      F       USA  \N       \N      \N      \N      \N      \N      \N      \N&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here I knew I wanted to look in the &lt;code&gt;person&lt;/code&gt; table, so I specified that in the call to &lt;code&gt;pg_dump&lt;/code&gt;, but this works as well when I want to search the entire database:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pg_dump  mydb | grep -i kilroy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;716565  public  person  18185   {&amp;#34;session_user&amp;#34;: &amp;#34;josh&amp;#34;}        {&amp;#34;id&amp;#34;: 633132}  {&amp;#34;last_name&amp;#34;: &amp;#34;Feeney44&amp;#34;}       {&amp;#34;last_name&amp;#34;: &amp;#34;Kilroy44&amp;#34;}       U       123349  2023-02-03 11:19:40.587883-062023-02-03 11:19:40.587883-06    2023-02-03 11:19:40.592103-06   josh    \N      \N
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;633132  F       NH      \N      Cristen212      J    Kilroy44        1983-09-28 00:00:00     \N      t       \N      \N      \N      \N      F       USA  \N       \N      \N      \N      \N      \N      \N      \N&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I can switch &lt;code&gt;pg_dump&lt;/code&gt; to &lt;code&gt;--inserts&lt;/code&gt; mode and thus see the table these entries were found in:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pg_dump --inserts mydb | grep -i kilroy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;INSERT INTO audit.modification_log VALUES (716565, &amp;#39;public&amp;#39;, &amp;#39;person&amp;#39;, 18185, &amp;#39;{&amp;#34;session_user&amp;#34;: &amp;#34;josh&amp;#34;}&amp;#39;, &amp;#39;{&amp;#34;id&amp;#34;: 633132}&amp;#39;, &amp;#39;{&amp;#34;last_name&amp;#34;: &amp;#34;Feeney44&amp;#34;}&amp;#39;, &amp;#39;{&amp;#34;last_name&amp;#34;: &amp;#34;Kilroy44&amp;#34;}&amp;#39;, &amp;#39;U&amp;#39;, 123349, &amp;#39;2023-02-03 11:19:40.587883-06&amp;#39;, &amp;#39;2023-02-03 11:19:40.587883-06&amp;#39;, &amp;#39;2023-02-03 11:19:40.592103-06&amp;#39;, &amp;#39;josh&amp;#39;, NULL, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;INSERT INTO public.person VALUES (633132, &amp;#39;F&amp;#39;, &amp;#39;NH&amp;#39;, NULL, &amp;#39;Cristen212&amp;#39;, &amp;#39;J&amp;#39;, &amp;#39;Kilroy44&amp;#39;, &amp;#39;1983-09-28 00:00:00&amp;#39;, NULL, true, NULL, NULL, NULL, NULL, &amp;#39;F&amp;#39;, &amp;#39;USA&amp;#39;, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But &lt;code&gt;pg_dump&lt;/code&gt; is considerably slower with &lt;code&gt;--inserts&lt;/code&gt; turned on (about 200% slower, in my rudimentary testing on this one database), so perhaps I can get fancier with &lt;code&gt;grep&lt;/code&gt; and achieve the same thing:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pg_dump mydb | grep -ie kilroy -e &amp;#39;^COPY&amp;#39; | grep -B1 -i kilroy
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;COPY audit.modification_log (id, table_schema, table_name, table_relid, app_user_info, id_columns, old_data, new_data, operation, transaction_id, ts_transaction, ts_statement, ts_clock, session_user_name, client_addr, query_text) FROM stdin;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;716565  public  person  18185   {&amp;#34;session_user&amp;#34;: &amp;#34;josh&amp;#34;}        {&amp;#34;id&amp;#34;: 633132}  {&amp;#34;last_name&amp;#34;: &amp;#34;Feeney44&amp;#34;}       {&amp;#34;last_name&amp;#34;: &amp;#34;Kilroy44&amp;#34;}       U       123349  2023-02-03 11:19:40.587883-062023-02-03 11:19:40.587883-06    2023-02-03 11:19:40.592103-06   josh    \N      \N
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;COPY public.person (id, birth_gender, ethnicity, language, first_name, middle_name, last_name, birth_date, date_of_death, live, days_old_no_birthday, from_pregnant_id, fatal_condition_id, death_status, current_gender, country_of_birth, people_id, entity_id, birth_gender_id, ethnicity_id, primary_language_id, age_type_id, approximate_age_no_birthday, updated_at) FROM stdin;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;633132  F       NH      \N      Cristen212      J    Kilroy44        1983-09-28 00:00:00     \N      t       \N      \N      \N      \N      F       USA  \N       \N      \N      \N      \N      \N      \N      \N&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But the other day I realized I could easily search every a single table without leaving the database, thanks to &lt;code&gt;\copy&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mydb=# \copy person to program &amp;#39;grep -i kilroy&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;COPY 117
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;633132  F       NH      \N      Cristen212      J    Kilroy44        1983-09-28 00:00:00     \N      t       \N      \N      \N      \N      F       USA  \N       \N      \N      \N      \N      \N      \N      \N&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;\copy&lt;/code&gt; requires copying the entire table to the client side, which wasn&amp;rsquo;t a concern in my instance but could be a problem for some folks, and you need to be a superuser to use server-side &lt;code&gt;COPY ... TO PROGRAM&lt;/code&gt;, so there are some limitations to this approach.&lt;/p&gt;
&lt;p&gt;I started thinking about this problem fresh off an encounter with row types, and realized we could do the whole thing in SQL:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mydb=# select * from person where person::text ~* &amp;#39;kilroy&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   id   | birth_gender | ethnicity | language | first_name |             middle_name              | last_name |     birth_date      | date_of_death | live | days_old_no_birthday | from_pregnant_id | fatal_condition_id | death_status | current_gender | country_of_birth | people_id | entity_id | birth_gender_id | ethnicity_id | primary_language_id | age_type_id | approximate_age_no_birthday | updated_at
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;--------+--------------+-----------+----------+------------+--------------------------------------+-----------+---------------------+---------------+------+----------------------+------------------+--------------------+--------------+----------------+------------------+-----------+-----------+-----------------+--------------+---------------------+-------------+-----------------------------+------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 633132 | F            | NH        |          | Cristen212 | J | Kilroy44  | 1983-09-28 00:00:00 |               | t    |                      |                  |                    |              | F              | USA              |           |           |                 |              |                     |             |                             |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(1 row)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is my new favorite way of solving this problem, when I know what table I&amp;rsquo;m looking in but don&amp;rsquo;t know the column. In cases where I don&amp;rsquo;t know either, there&amp;rsquo;s always this monstrosity:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mydb=# select &amp;#39;select &amp;#39; || quote_literal(relname) || &amp;#39; as relname, f.*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;from &amp;#39; || oid::regclass || &amp;#39; f where f::text ~* &amp;#39;&amp;#39;kilroy&amp;#39;&amp;#39;&amp;#39; from pg_class
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;where relkind = &amp;#39;r&amp;#39; and relnamespace = &amp;#39;public&amp;#39;::regnamespace; \gexec&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will work only in &lt;code&gt;psql&lt;/code&gt;, as it depends on the &lt;code&gt;\gexec&lt;/code&gt; command. It composes one query for each table, and then executes them in turn. It produces rather a lot of probably useless output you&amp;rsquo;ll need to sort through, and if you have (as I do) some tables with a large number of columns, I recommend trying it with &lt;code&gt;\x&lt;/code&gt; turned on, to avoid having to page through quite so many results. But it did work, to find the entry I was looking for:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;... Lots of output
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(0 rows)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-[ RECORD 1 ]---------------+-------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;relname                     | person
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;id                          | 633132
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;birth_gender                | F
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ethnicity                   | NH
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;language                    |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;first_name                  | Cristen212
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;middle_name                 | J
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;last_name                   | Kilroy44
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;birth_date                  | 1983-09-28 00:00:00
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;date_of_death               |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;live                        | t
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;days_old_no_birthday        |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;from_pregnant_id            |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fatal_condition_id          |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;death_status                |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;current_gender              | F
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;country_of_birth            | USA
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;people_id                   |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;entity_id                   |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;birth_gender_id             |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ethnicity_id                |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;primary_language_id         |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;age_type_id                 |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;approximate_age_no_birthday |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;updated_at                  |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(0 rows)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;... Lots more output&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If I&amp;rsquo;m willing to expand beyond one-liner solutions, I can get &lt;code&gt;psql&lt;/code&gt; to filter that useless output for me:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mydb=# \o | grep -i kilroy | grep -v select
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mydb=# select &amp;#39;select &amp;#39; || quote_literal(relname) || &amp;#39; as rname, f.* from &amp;#39; || oid::regclass || &amp;#39; f where f::text ~* &amp;#39;&amp;#39;kilroy&amp;#39;&amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;from pg_class where relkind = &amp;#39;r&amp;#39; and relnamespace = &amp;#39;public&amp;#39;::regnamespace; \gexec
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mydb=# \o
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; person | 633132 | F            | NH        |          | Cristen212 | J | Kilroy44  | 1983-09-28 00:00:00 |               | t    |                      |                  |                    |              | F              | USA              |           |           |                 |              |                     |             |                             |&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When I did this, I had to use a final &lt;code&gt;\o&lt;/code&gt; to set the output mode back to normal, before I saw results.&lt;/p&gt;
&lt;p&gt;Do you have a different technique to solve this problem? I&amp;rsquo;m sure there are many other possibilities out there! Comment below!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Data Migration Tips</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2023/02/migration-tips-and-tricks/"/>
      <id>https://www.endpointdev.com/blog/2023/02/migration-tips-and-tricks/</id>
      <published>2023-02-04T00:00:00+00:00</published>
      <author>
        <name>Josh Tolley</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2023/02/migration-tips-and-tricks/leaves.webp&#34; alt=&#34;Scattered leaves on grass fill the frame, made up of many colors; green, cyan, pale and bright yellow, with red leaves providing highlights&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Seth Jensen, 2022 --&gt;
&lt;p&gt;When you&amp;rsquo;re in the business of selling software to people, you tend to get a few chances to migrate data from their legacy software to your shiny new system. Most recently for me that has involved public health data exported from legacy disease surveillance systems into &lt;a href=&#34;/expertise/postgresql/&#34;&gt;PostgreSQL databases&lt;/a&gt; for use by the open source EpiTrax system and its companion EMSA.&lt;/p&gt;
&lt;p&gt;We have collected a few tips that may help you learn from our successes,
as well as our &lt;del&gt;mistakes&lt;/del&gt;particularly educational experiences.&lt;/p&gt;
&lt;h3 id=&#34;customer-management&#34;&gt;Customer Management&lt;/h3&gt;
&lt;p&gt;Your job is to satisfy your customers, and &lt;strong&gt;your customers want to know how
the migration is progressing&lt;/strong&gt;. Give them an answer, even if it&amp;rsquo;s just a
generalization. This may be a burndown chart, a calculated percentage, a nifty
graphic, or whatever, but something your project managers can show to their
managers, to know more or less how far along things are.&lt;/p&gt;
&lt;p&gt;Your job is also to know your system; that&amp;rsquo;s not the customer&amp;rsquo;s job. They
shouldn&amp;rsquo;t have to get their data into a specific format for you to make use of
it. &lt;strong&gt;Be as flexible as possible&lt;/strong&gt; in the data format and structure
you&amp;rsquo;ll accept. In theory, so long as your customer can provide the legacy data
in a machine-readable format, you should be able to use it. Let them focus on
getting the data out of their legacy system — which is sometimes quite an
effort in itself! Real data is almost always messy data, and your customer will
probably want to take the opportunity to clean things up; make it as easy as
possible for them to do that, while still ensuring the migration proceeds
quickly and smoothly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Be careful about the vocabulary you use&lt;/strong&gt; with your customer. Your system and
the legacy system probably deal with the same kinds of data, and do generally
the same kinds of things. Of course, your software does it better than the
old &amp;rsquo;n&amp;rsquo; busted mess you&amp;rsquo;re replacing, but in order to be better, your software
has to be different from what it&amp;rsquo;s replacing. Different software means
different methods, different processes, and different concepts. You and your
customer might use the same words to mean totally different things, and unless
you&amp;rsquo;re careful, those differences can remain hidden well into the
implementation process, coming to light just in time to highlight some horrible
mistake you&amp;rsquo;ve made. Try to avoid that. Talk with your customer to make sure
your team and their team share a common vocabulary. If your system&amp;rsquo;s core
function is to track widgets, and their legacy system&amp;rsquo;s function is also to
track widgets, make sure you understand the differences between your software&amp;rsquo;s
concept of a widget and their legacy system&amp;rsquo;s concept of a widget.&lt;/p&gt;
&lt;h3 id=&#34;migration-scripting&#34;&gt;Migration Scripting&lt;/h3&gt;
&lt;p&gt;For our products and our customers, we&amp;rsquo;ve found pretty much every migration
process is different, and each one is a custom programming job. Your team
should &lt;strong&gt;decide at the beginning what steps the migration needs to include,
and what technologies it will use&lt;/strong&gt; in each step. Here at End Point, we often
like to work directly in the database, in SQL. Migrations are all about
manipulating data, and SQL is well suited for that task. With whatever
technology you use, decide how you&amp;rsquo;ll use it, to manage the considerations
given here. You can change your mind later and refactor accordingly, but always
have a plan you&amp;rsquo;re following.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Design the migration as a sequence of processes.&lt;/strong&gt; That is, first you might
import one type of record, next another type of record that depends on the
previous one, followed by several further steps to import data from a third
source, clean it, map values from the legacy system to the new system, validate
the results, and create records in the destination database. Of course the
steps will vary from project to project, but the point is your migration will
probably include several steps which need to be run in a specific order, so
plan your development conventions accordingly. At End Point, we often like to
&lt;strong&gt;put each step in a SQL file, and name each file beginning with a number&lt;/strong&gt;, so
you can run each script in order sorted by filename, and achieve the correct
result. We might have files called:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;01_import_products.sql&lt;/li&gt;
&lt;li&gt;02_import_customers.sql&lt;/li&gt;
&lt;li&gt;03_import_order_history.sql&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s also common to implement each step one at a time, and to need to run each
step several times as it&amp;rsquo;s being developed. We find it very helpful to &lt;strong&gt;wrap
each step in a transaction&lt;/strong&gt;. Often that means each SQL file begins with a
&lt;code&gt;BEGIN;&lt;/code&gt; statement, and ends with &lt;code&gt;COMMIT;&lt;/code&gt;. Often I&amp;rsquo;ll leave out the &lt;code&gt;COMMIT&lt;/code&gt;
until I&amp;rsquo;m finished working on a file. That way to work on the code I can open a
database session and run the migration script I&amp;rsquo;m working on, and when it
completes, it will leave me inside the open transaction where I can inspect the
results of my work. I make changes to the script, roll back the transaction,
and run the script again, for as many iterations as it takes. I only add a
&lt;code&gt;COMMIT&lt;/code&gt; when I&amp;rsquo;ve tested the whole file and think it&amp;rsquo;s ready for the next step
in testing.&lt;/p&gt;
&lt;p&gt;I mentioned above that the customer may want to use this opportunity to clean
their data. You should want this, too. &lt;strong&gt;Make sure the data you&amp;rsquo;re feeding your
new system is as clean and well-structured as possible.&lt;/strong&gt; You may find, as we
do, that most of the work in your migrations is in validating the input data,
and that actually creating new records in your application is almost an
afterthought. That&amp;rsquo;s OK. You may also find there are places where your
application, wonderful though it may be, could stand to be more strict about
the data it accepts. I have often discovered my application&amp;rsquo;s database needs a uniqueness
constraint, or a foreign key, thanks to a migration I was working on.&lt;/p&gt;
&lt;h3 id=&#34;data-migration-history&#34;&gt;Data Migration History&lt;/h3&gt;
&lt;p&gt;I wish I could truthfully claim all our migrations go off flawlessly, but that
would be a lie. It&amp;rsquo;s not unheard of to run into some corner case, a few weeks
or even months after the migration goes live, where data wasn&amp;rsquo;t migrated correctly.&lt;/p&gt;
&lt;p&gt;On the other hand, it&amp;rsquo;s certainly not uncommon for a customer or coworker to
spot something that strikes them as odd, after the migration goes live, only to
find later that everything was in fact correct. In either case, it&amp;rsquo;s important
to &lt;strong&gt;preserve a history of the migration&lt;/strong&gt; to investigate these concerns. We
accomplish this with a few specific steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a database schema for the migration, and a table within that schema for each data file or object type we&amp;rsquo;re importing.&lt;/strong&gt; I call these tables &amp;ldquo;staging tables&amp;rdquo;, where the incoming data is &amp;ldquo;staged&amp;rdquo; as it&amp;rsquo;s cleaned and validated. Having a separate schema means these tables can remain in the production database long after the migration is complete, generally without interfering with anything.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;These staging tables should generally &lt;strong&gt;use text fields, to be as forgiving and flexible as possible with the incoming data.&lt;/strong&gt; We can clean, parse, and reformat the data after it&amp;rsquo;s imported.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Don&amp;rsquo;t change the data in these staging tables; add to the data instead.&lt;/strong&gt; In other words, if you need to map a value from the legacy system to a different value for your new system, don&amp;rsquo;t change the column you imported into the staging table; instead, add a new column to the staging table where you&amp;rsquo;ll store the re-mapped value. If you need to parse a text field into a date (because you followed the instruction to use text fields!), don&amp;rsquo;t change the type of an imported column; instead, add a new column of date or timestamp type, to store the parsed value. That way, when three months down the road someone discovers that some of the imported records have weird dates, you have all the information you need to determine whether the fault lies with the imported data or some step of the migration progress. Knowing exactly where the fault crept in leaves you that much more empowered to fix it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Keep track of your migrated records&amp;rsquo; primary keys, in the legacy system and the new system.&lt;/strong&gt; Imagine you&amp;rsquo;ve just imported your client&amp;rsquo;s legacy customer list into a staging table. This data includes the legacy system&amp;rsquo;s primary key. Add a new column to the table for your new system&amp;rsquo;s primary key, and populate it. Many of our systems use an integer sequence as a primary key, so we&amp;rsquo;d add a new integer column to the staging table, and fill it with the next values from the sequence. Following this principle will give you several important abilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can always connect a record in the legacy system with its corresponding record(s) in the new system. If you&amp;rsquo;ve imported a customer list in this fashion, then when you&amp;rsquo;re importing the order data later, and each order points to a customer using a legacy customer primary key, you can easily find the correct customer primary key to use in your system.&lt;/li&gt;
&lt;li&gt;You can easily know if a record in your system comes from the migration, or from normal day-to-day business. You will probably use this every time you try to debug something with your migration.&lt;/li&gt;
&lt;li&gt;If you need to remove all imported records and re-import them, you can identify exactly which records those are. This should be only rarely needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, &lt;strong&gt;document the decision making process, in comments directly in your
code.&lt;/strong&gt; For instance, if you have a table of mappings from one value to
another, chances are good you arrived at the final version of that mapping
table only after some discussion with the customer. Chances are also good
someone&amp;rsquo;s going to question it later on. It&amp;rsquo;s helpful to keep a comment around,
something like, &lt;code&gt;# Joe Rogers verified this is the correct mapping in the daily standup meeting, 23 Nov 2022&lt;/code&gt;. This is especially common if you
eventually decide to ignore a certain class of records. &lt;code&gt;/* Rebecca says ignore all records with type = &amp;quot;ARCHIVED&amp;quot;, via group email 9 Jan 2023 */&lt;/code&gt; is a very
helpful clue when someone comes around wondering where those records went.&lt;/p&gt;
&lt;h3 id=&#34;teamwork&#34;&gt;Teamwork&lt;/h3&gt;
&lt;p&gt;My remaining tips apply to almost any programming project. First, &lt;strong&gt;use source
control, and commit your code to it often.&lt;/strong&gt; I can&amp;rsquo;t count how often I&amp;rsquo;ve been
grateful the Git repository had a backup of my work, or made my work accessible
to fill some unexpected need on some other system, nor can I count how many
times I&amp;rsquo;ve been stuck because someone else didn&amp;rsquo;t commit their code so I
couldn&amp;rsquo;t get at it when I needed it.  Let&amp;rsquo;s not talk about how many times I&amp;rsquo;ve
caused someone else to get stuck in the same way&amp;hellip; Of course, don&amp;rsquo;t commit
your customer&amp;rsquo;s data. But you should commit your code, and commit it often.&lt;/p&gt;
&lt;p&gt;Finally, where possible, &lt;strong&gt;work with someone else.&lt;/strong&gt; Two programmers reviewing
each other&amp;rsquo;s code and collaborating on solutions are often far better than two
programmers working alone, or one programmer working twice as much.&lt;/p&gt;
&lt;p&gt;Speaking of working out solutions together, I&amp;rsquo;d love your help improving this
list. What keys have you found are important for data migration projects? I
welcome your comments. And if you&amp;rsquo;re looking for someone to handle a data
migration project for you, &lt;a href=&#34;/contact/&#34;&gt;give us a call&lt;/a&gt;!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>What is serialization?</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2021/05/what-is-serialization/"/>
      <id>https://www.endpointdev.com/blog/2021/05/what-is-serialization/</id>
      <published>2021-05-06T00:00:00+00:00</published>
      <author>
        <name>Zed Jensen</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2021/05/what-is-serialization/banner.jpg&#34; alt=&#34;Mailbox&#34;&gt;
Photo by &lt;a href=&#34;https://unsplash.com/@briantagalog&#34;&gt;Brian Patrick Tagalog&lt;/a&gt; on &lt;a href=&#34;https://unsplash.com/photos/axwRgfER-sA&#34;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Serialization is a process used constantly by most applications today. However, there are some common misconceptions and misunderstandings about what it is and how it works; I hope to clear up a few of these in this post. I’ll be talking specifically about serialization and not marshalling, a related process.&lt;/p&gt;
&lt;h3 id=&#34;what-is-serialization&#34;&gt;What is serialization?&lt;/h3&gt;
&lt;p&gt;Most developers know that complex objects need to be transformed into another format before they can be sent to a server, but many might not be aware that every time they print an object in the Python or JavaScript console, the same type of thing is happening. Variables and objects as they’re stored in memory—either in a headless program or one with developer tools attached—are not really usable to us humans.&lt;/p&gt;
&lt;p&gt;Data serialization is the process of taking an object in memory and translating it to another format. This may entail encoding the information as a chunk of binary to store in a database, creating a string representation that a human can understand, or saving a config file from the options a user selected in an application. The reverse—deserialization—takes an object in one of these formats and converts it to an in-memory object the program can work with. This two-way process of translation is a very important part of the ability of various programs and computers to communicate with one another.&lt;/p&gt;
&lt;p&gt;An example of serialization that we deal with every day can be found in the way we view numbers on a calculator. Computers use binary numbers, not decimal, so how do we ask one to add 230 and 4 and get back 234? Because the 230 and the 4 are deserialized to their machine representations, added in that format, and then serialized again in a form we understand: 234. To get 230 in a form the computer understands, it has to read each digit one at a time, figure out what that digit’s value is (i.e. the 2 is 200 and the 3 is 30), and then add them together. It’s easy to overlook how often this concept appears in everything we do with computers!&lt;/p&gt;
&lt;h3 id=&#34;why-its-important-to-understand-how-it-works&#34;&gt;Why it’s important to understand how it works&lt;/h3&gt;
&lt;p&gt;As a developer, there are many reasons you should be familiar with how serialization works as well as the various formats available, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Different formats are best suited for different use cases.&lt;/li&gt;
&lt;li&gt;Standardization varies between formats. For example, INI files have no single specification, but TOML does. YAML 1.2 came out in 2009 but most YAML parsers still implement only parts of the earlier YAML 1.1 spec.&lt;/li&gt;
&lt;li&gt;Each application typically supports only one or a few formats.&lt;/li&gt;
&lt;li&gt;Formats have different goals, such as readability &amp;amp; simplicity for humans, speed for computers, and conciseness for storage space and transfer efficiency.&lt;/li&gt;
&lt;li&gt;Applications use the various formats very differently from each other.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before you start working on a project, it will certainly pay off to make sure you’re familiar with the options for serialization formats so you can pick the one most suited to your particular use case.&lt;/p&gt;
&lt;h3 id=&#34;binary-vs-human-readable-serialization&#34;&gt;Binary vs. human-readable serialization&lt;/h3&gt;
&lt;p&gt;There’s one more important distinction to be made before I show any examples, and that is human-readable vs. binary serialization. The advantage of human-readability is obvious: debugging in particular is much simpler, but other things like scanning data for keywords is much easier as well. Binary serialization, however, can be much faster to process for both the sender and recipient, it can sometimes include information that’s hard to represent in plain text, and it can be much more efficient with space without needing separate compression. I’ll stick to reviewing human-readable formats in this post.&lt;/p&gt;
&lt;h3 id=&#34;common-serialization-formats-with-examples&#34;&gt;Common serialization formats with examples&lt;/h3&gt;
&lt;h4 id=&#34;csv&#34;&gt;CSV&lt;/h4&gt;
&lt;p&gt;For my examples, I’ll have a simple JavaScript object representing myself, with properties including my name, recent books I’ve read, and my favorite food. I’ll start with &lt;a href=&#34;https://en.wikipedia.org/wiki/Comma-separated_values&#34;&gt;CSV&lt;/a&gt; (comma-separated values) because it’s intended for simpler data records than most of the other formats I’ll be showing; you’ll notice that there isn’t an easy way to do object hierarchies or lists. CSV files begin with a list of the column names followed by the rows of data:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-csv&#34; data-lang=&#34;csv&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;name&lt;/span&gt;,&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;favorite_food_name&lt;/span&gt;,&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;favorite_food_prep_time&lt;/span&gt;,&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;recent_book&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;Zed&lt;/span&gt;,&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;Pizza&lt;/span&gt;,&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;30&lt;/span&gt;,&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;Leviathan Wakes&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;CSV files are most often used for storing or transferring tabular data, but there’s no single specification, so the implementation can be fairly different in different programs. The most common differences involve data with commas or line breaks, requiring quoting of some or all elements, and escaping some characters.&lt;/p&gt;
&lt;h4 id=&#34;tsv&#34;&gt;TSV&lt;/h4&gt;
&lt;p&gt;Files in tab-separated values (TSV) format are also fairly common, using tabs instead of commas to separate columns of data.&lt;/p&gt;
&lt;p&gt;Because the tab character is rarely used in text put into table format, it is less of a problem as a separator than the very frequently-occurring comma. Typically no quoting or escaping of any kind is needed or possible in a TSV file.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;name	favorite_food_name	favorite_food_prep_time	recent_book
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Zed	Pizza	30	Leviathan Wakes&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For the rest of my examples of each format, I’ll show the command (and library, if needed) that I used to get the serialized form of my object.&lt;/p&gt;
&lt;h4 id=&#34;json&#34;&gt;JSON&lt;/h4&gt;
&lt;p&gt;&lt;a href=&#34;https://www.json.org/json-en.html&#34;&gt;JSON&lt;/a&gt; stands for JavaScript Object Notation, and thus you might be fooled into thinking that it’s just an extension of JavaScript itself. However, this isn’t the case; it was originally derived from JavaScript syntax, but it has significant differences. For example, JSON has a stricter syntax for declaring objects. For my example, using the Google Chrome developer console I declared my object like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; me = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  name: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Zed&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  recent_books: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Leviathan Wakes&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Pride and Prejudice and Zombies&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  favorite_food: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    name: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Pizza&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    prep_time: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You’ll notice that the property names aren’t quoted and the strings are single-quoted with &lt;code&gt;&#39;&lt;/code&gt;. This is perfectly valid JavaScript, but invalid JSON. Let’s see what an equivalent JSON file could look like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Zed&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;recent_books&amp;#34;&lt;/span&gt;: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Leviathan Wakes&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Pride and Prejudice and Zombies&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;favorite_food&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Pizza&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;prep_time&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;JSON requires property names to be quoted, and only double quotes &lt;code&gt;&amp;quot;&lt;/code&gt; are allowed. It’s true that they look very similar, but the difference is important. Also notice that this JSON is formatted in an easy-to-read way, on multiple lines with indentation. This is called pretty-printing and is possible because JSON doesn’t care about whitespace.&lt;/p&gt;
&lt;p&gt;Imagine my JavaScript application wants to send this object to some server that’s expecting JSON, using any other platform such as Java or .NET and not necessarily JavaScript. It would need to serialize the object from memory into a JSON string first, which can be done by JavaScript itself:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;let&lt;/span&gt; meJSON = JSON.stringify(me);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; console.log(meJSON);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Zed&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;recent_books&amp;#34;&lt;/span&gt;:[&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Leviathan Wakes&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Pride and Prejudice and Zombies&amp;#34;&lt;/span&gt;],&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;favorite_food&amp;#34;&lt;/span&gt;:{&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Pizza&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;prep_time&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;30&lt;/span&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that the result here has no extra line breaks or spaces. This is called minifying, and is the reverse of pretty-printing. The flexibility allowed by these two processes is one reason people like JSON.&lt;/p&gt;
&lt;p&gt;Parsing our example back into a JavaScript object is also very easy:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; console.log(JSON.parse(meJSON));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  name: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Zed&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  recent_books: [ &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Leviathan Wakes&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Pride and Prejudice and Zombies&amp;#39;&lt;/span&gt; ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  favorite_food: { name: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Pizza&amp;#39;&lt;/span&gt;, prep_time: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;30&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The easy integration with JavaScript is a big reason JSON is so popular. I showed these examples to highlight how easy it is to use, but also to point out that sometimes we might use serialization without being aware of what’s going on under the hood; it’s important to remember that JSON texts aren’t JavaScript objects, and there may be instances where it makes more sense to use another format.&lt;/p&gt;
&lt;p&gt;For instance, if you need a config file format that’s easy for humans to read, it is very helpful to allow comments that are not part of the data structure once it is read into memory. But CSV, TSV, and JSON do not allow for comments. The most obvious or popular choice isn’t always the only one, or the best one, so let’s keep looking at other formats.&lt;/p&gt;
&lt;h4 id=&#34;xml&#34;&gt;XML&lt;/h4&gt;
&lt;p&gt;&lt;a href=&#34;https://www.w3.org/XML/&#34;&gt;XML&lt;/a&gt; is well known as the markup language of which HTML is a subset, or at least a close sibling. It can also be used for serialization of data, and allows us to add comments such as the one at the beginning:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- My favorites as of May 2021 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;name&amp;gt;&lt;/span&gt;Zed&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;recent_books&amp;gt;&lt;/span&gt;Leviathan Wakes&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/recent_books&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;recent_books&amp;gt;&lt;/span&gt;Pride and Prejudice and Zombies&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/recent_books&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;favorite_food&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;name&amp;gt;&lt;/span&gt;Pizza&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;prep_time&amp;gt;&lt;/span&gt;30&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/prep_time&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/favorite_food&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;XML has the benefit of being widely used, and it can represent more complex data structures since each element can also optionally have various attributes, and ordering of its child elements is significant.&lt;/p&gt;
&lt;p&gt;But XML is unpleasant to type and for many use cases feels rather complex and bloated, so it suffers when compared to other formats we are looking at in this post.&lt;/p&gt;
&lt;h4 id=&#34;yaml&#34;&gt;YAML&lt;/h4&gt;
&lt;p&gt;&lt;a href=&#34;https://yaml.org/&#34;&gt;YAML&lt;/a&gt; is a serialization format for all kinds of data that’s designed to be human-readable. Simple files look fine, like our example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;---&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#888&#34;&gt;# My favorites as of May 2021&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;name&lt;/span&gt;:&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Zed&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;recent_books&lt;/span&gt;:&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;  &lt;/span&gt;- &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Leviathan Wakes&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;  &lt;/span&gt;- &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Pride and Prejudice and Zombies&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;favorite_food&lt;/span&gt;:&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;name&lt;/span&gt;:&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;pizza&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;prep_time&lt;/span&gt;:&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;30&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, the YAML specification is far from simple, and quite a bit has been written on why it’s better to use other formats where possible:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/cblp/yaml-sucks&#34;&gt;YAML sucks.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.arp242.net/yaml-config.html&#34;&gt;YAML: probably not so great after all&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://allan.reyes.sh/programming/2018/06/20/The-YAML-NOrway-Law.html&#34;&gt;The YAML-NOrway Law&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;ini&#34;&gt;INI&lt;/h4&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/INI_file&#34;&gt;INI&lt;/a&gt;, short for &lt;em&gt;initialization&lt;/em&gt;, is well-known and has been around since the ’90s or earlier. It was most notably used for configuration files in Windows, especially in the era before Windows 95. INI files are still used in many places, including Windows and Linux programs’ system configuration files such as for the Git version control system.&lt;/p&gt;
&lt;p&gt;Our example in INI format looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;; My favorites as of May 2021&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;name&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;Zed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;recent_books[]&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;Leviathan Wakes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;recent_books[]&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;Pride and Prejudice and Zombies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;[favorite_food]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;name&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;Pizza&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;prep_time&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;30&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;INI has no single specification, so one project’s config files might use different syntax from another. This makes it hard to recommend over newer formats like TOML.&lt;/p&gt;
&lt;h4 id=&#34;toml&#34;&gt;TOML&lt;/h4&gt;
&lt;p&gt;&lt;a href=&#34;https://toml.io/en/&#34;&gt;TOML&lt;/a&gt;, which stands for Tom’s Obvious Minimal Language, is a more recent addition to serialization formats; its first version was released in 2013. TOML maps directly to dictionary objects and is intended especially for configuration files as an alternative to INI. It has similar syntax to INI as well:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# My favorites as of May 2021&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;name = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Zed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;recent_books = [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Leviathan Wakes&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Pride and Prejudice and Zombies&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[favorite_food]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;name = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Pizza&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;prep_time = &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;30&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Unlike INI and YAML, TOML has a very clear and well-defined specification, and seems like a great option for new projects in the future. It is currently used most prominently by the Rust programming language tools. There is a list of TOML libraries per language and version on the &lt;a href=&#34;https://github.com/toml-lang/toml/wiki&#34;&gt;TOML wiki at GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&#34;phps-serialize&#34;&gt;PHP’s serialize()&lt;/h4&gt;
&lt;p&gt;&lt;a href=&#34;https://www.php.net/manual/en/function.serialize.php&#34;&gt;PHP’s serialization output&lt;/a&gt; isn’t quite as readable, but the data is still recognizable for someone scanning visually for keywords or doing a more rigorous search. Converting from JSON is fairly simple:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;#!/usr/bin/env php
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;?php
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$json&lt;/span&gt; = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;  &amp;#34;name&amp;#34;: &amp;#34;Zed&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;  &amp;#34;recent_books&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;    &amp;#34;Leviathan Wakes&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;    &amp;#34;Pride and Prejudice and Zombies&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;  ],
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;  &amp;#34;favorite_food&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;    &amp;#34;name&amp;#34;: &amp;#34;Pizza&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;    &amp;#34;prep_time&amp;#34;: 30
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$obj&lt;/span&gt; = json_decode(&lt;span style=&#34;color:#369&#34;&gt;$json&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;echo&lt;/span&gt; serialize(&lt;span style=&#34;color:#369&#34;&gt;$obj&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And the result:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;a:3:{s:4:&amp;#34;name&amp;#34;;s:3:&amp;#34;Zed&amp;#34;;s:12:&amp;#34;recent_books&amp;#34;;a:2:{i:0;s:15:&amp;#34;Leviathan Wakes&amp;#34;;i:1;s:27:&amp;#34;Pride and Prejudice and Zombies&amp;#34;;}s:13:&amp;#34;favorite_food&amp;#34;;a:2:{s:4:&amp;#34;name&amp;#34;;s:5:&amp;#34;Pizza&amp;#34;;s:9:&amp;#34;prep_time&amp;#34;;i:30;}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;PHP serialize() does not allow for comments, but it does support full object marshalling, which it is more commonly used for.&lt;/p&gt;
&lt;h4 id=&#34;perls-datadumper&#34;&gt;Perl’s Data::Dumper&lt;/h4&gt;
&lt;p&gt;Perl’s &lt;a href=&#34;https://metacpan.org/pod/Data::Dumper&#34;&gt;Data::Dumper&lt;/a&gt; module serializes data in a format specifically for Perl to load back into memory:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;#!/usr/bin/env perl&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;strict&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;warnings&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;JSON&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Data::Dumper&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Dumper&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$json&lt;/span&gt; = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;lt;&amp;lt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;END&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;  &amp;#34;name&amp;#34;: &amp;#34;Zed&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;  &amp;#34;recent_books&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;    &amp;#34;Leviathan Wakes&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;    &amp;#34;Pride and Prejudice and Zombies&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;  ],
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;  &amp;#34;favorite_food&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;    &amp;#34;name&amp;#34;: &amp;#34;Pizza&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;    &amp;#34;prep_time&amp;#34;: 30
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;END&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;my&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$hash&lt;/span&gt; = decode_json &lt;span style=&#34;color:#369&#34;&gt;$json&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;print&lt;/span&gt; Dumper(&lt;span style=&#34;color:#369&#34;&gt;$hash&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And the result, which is a valid Perl statement:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-perl&#34; data-lang=&#34;perl&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$VAR1&lt;/span&gt; = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;recent_books&amp;#39;&lt;/span&gt; =&amp;gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Leviathan Wakes&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Pride and Prejudice and Zombies&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Zed&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;favorite_food&amp;#39;&lt;/span&gt; =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                               &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Pizza&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                               &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;prep_time&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                             }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Serialization is an extremely common function that we as programmers should be familiar with. Knowing which is a good option for a new project can save time and money, as well as making things easier for developers and API users.&lt;/p&gt;
&lt;p&gt;Please leave a comment if I have missed your favorite format!&lt;/p&gt;
&lt;h4 id=&#34;further-reading&#34;&gt;Further reading&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Serialization&#34;&gt;Serialization on Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Marshalling_(computer_science)&#34;&gt;Marshaling on Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

      </content>
    </entry>
  
    <entry>
      <title>The flow of hierarchical data extraction</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2019/03/the-flow-of-hierarchical-data-extraction/"/>
      <id>https://www.endpointdev.com/blog/2019/03/the-flow-of-hierarchical-data-extraction/</id>
      <published>2019-03-13T00:00:00+00:00</published>
      <author>
        <name>Árpád Lajos</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2019/03/the-flow-of-hierarchical-data-extraction/art-ball-ball-shaped-235615-smaller.jpg&#34; alt=&#34;forest view through glass ball on wood stump&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;1-problem-statement&#34;&gt;1. Problem statement&lt;/h3&gt;
&lt;p&gt;There are many cases when people intend to collect data, for various purposes. One may want to compare prices or find out how musical fashion changes over time. There are a zillion potential uses of collected data.&lt;/p&gt;
&lt;p&gt;The old-fashioned way to do this task is to hire a few dozen of people and explain them where should they go on the web, what should they collect, how they should write a report and how they should send it.&lt;/p&gt;
&lt;p&gt;It is more effective to teach them this at the same time than to teach them separately, but even then, there will be misunderstandings, mistakes with high cost, not to mention the limit a human has when processing data in terms of the amount to process. As a result, the industry strives to make sure this is as automatic as possible.&lt;/p&gt;
&lt;p&gt;This is why people write software to cope with this issue. The terms data-extractor, data-miner, data-crawler, data-spider mean software which extracts data from a source and stores it at the target. If data is mined from the web, then the more-specific web-extractor, web-miner, web-crawler, web-spider terms can be used.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2019/03/the-flow-of-hierarchical-data-extraction/SemanticDataExtractorFigure1.png&#34; alt=&#34;&#34; title=&#34;Extraction, to put it simply&#34;&gt;&lt;/p&gt;
&lt;p&gt;In this article I will use the term “data-miner”.&lt;/p&gt;
&lt;p&gt;This article deals with the extraction of hierarchical data in semantic manner and the way we can parse the data we obtained this way.&lt;/p&gt;
&lt;h4 id=&#34;11-hierarchical-structure&#34;&gt;1.1. Hierarchical structure&lt;/h4&gt;
&lt;p&gt;A hierarchical structure involves a hierarchy, that is, we have a graph involved with nodes and vertices, but without a cycle. Specialists call this structure a &lt;strong&gt;forest&lt;/strong&gt;. A forest consists of &lt;strong&gt;trees&lt;/strong&gt;; in our case we have a forest of rooted trees. A rooted tree has a root node and every other node is its descendant (child of child of child …), or, if we put it inversely, the root is the ancestor of all other nodes in a rooted tree.&lt;/p&gt;
&lt;p&gt;If we add a node to a forest and we make sure that all the trees’ roots in the forest are children of the new node, the new root, then we transformed our hierarchical structure, our forest into a tree.&lt;/p&gt;
&lt;p&gt;Common hierarchical structures a data-miner might have to work with are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTML&lt;/li&gt;
&lt;li&gt;XML&lt;/li&gt;
&lt;li&gt;Trees represented in JSON&lt;/li&gt;
&lt;li&gt;File structure&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other, non-hierarchical structures could be texts, pictures, audio files, video, etc. In this article we focus on hierarchical structures.&lt;/p&gt;
&lt;h4 id=&#34;12-purpose-of-the-data-miner&#34;&gt;1.2. Purpose of the data-miner&lt;/h4&gt;
&lt;p&gt;Of course the purpose of the data-miner is to mine data; however, more specifically, we can speak about general-purpose data-miners, thematic data-miners and narrow-spaced data-miners.&lt;/p&gt;
&lt;p&gt;General-purpose data-miners are the data-miners which extract and prepare data for search engines. The technique one can imagine is to find the text in the source (for example a web-page) and map it to keywords, so that when people are searching for the keywords, the source is shown as the result. Of course, it is highly probable that these data-miners are much more smart and complex than described here, but that is out of scope from our perspective.&lt;/p&gt;
&lt;p&gt;If we speak about general-purpose data-mining, then even if it is to mine from a hierarchical data-source, it is very difficult to define all the semantics involved by humans, so, if one wants to create a general-purposed data-miner, machine-learning will play a large part to define all the concepts. However, a general-purposed data-miner is a generalized version of thematic data-miner. If we add up a lot of thematic data-miners, we get a general-purpose data-miner and inversely, if we divide the different areas a general-purposed data-miner deals with, we get thematic data-miners. This is true if we look at what they accomplish, but the implementation will differ a lot when the developers implement a general-purposed data-miner from the case when developers implement a thematic data-miner. As a result, when we discuss the thematic data-miners, we can keep in mind that the general-purposed data-miners are a broader version of the same thing, at least if we look at what they achieve.&lt;/p&gt;
&lt;p&gt;Thematic data-miners are dealing with a given cluster of concepts, that is, concepts which are logically related to each-other. For example, if we are to extract real-estate details, then we have concepts of “type”, “bedroom number”, “picture” and so on. All these concepts are interrelated; the cluster is defined by the real-estate entity we want to extract. If we speak of the “type”, we really mean “the type of the real estate” entity.&lt;/p&gt;
&lt;p&gt;Narrow-spaced data-miners are data-miners which extract data from very specific data-sources, like a single website. These data-miners are always particular cases of thematic data-miners, however, in many cases narrow-spaced data-miners have a lot of hard-coded logic, so, when the space of a narrow-spaced thematic data-miner is broadened, there is usually a lot of code refactoring involved.&lt;/p&gt;
&lt;p&gt;This article focuses on thematic data-miners, which could have thousands of different sources.&lt;/p&gt;
&lt;h4 id=&#34;13-the-human-element&#34;&gt;1.3. The human element&lt;/h4&gt;
&lt;p&gt;We need to pay attention to legality and to the ethical aspect. If data mining from the source is illegal, then we must avoid doing it. If it is against the will of those who own it, then it is unethical and we should avoid it. Sources should be at least neutral to our extraction, but, preferably happy about us extracting their data.&lt;/p&gt;
&lt;p&gt;Why would the owner of a data source be against extracting their data? There can be many possible causes. For example, the owner might want to attract many human visitors to a website, who would visit to see their data and would be unhappy if another website were created and people would visit the new website instead of theirs.&lt;/p&gt;
&lt;p&gt;But why would the owner of a data source be happy about extracting their data? It depends on the purpose of their data. If the purpose is to spread the information as far as possible, then data extractors are considered to be “helping hands”.&lt;/p&gt;
&lt;p&gt;For example, if an estate agent of a small village wants to target global audience, he/she might want to create a website and hope that people would see his/her data, but without advertisement and a lot of care to raise the popularity of the site, including design, SEO measures and so on, people searching for real estate might never see his/her site. A large website which is searchable by region and shows the results of extracted data could boost the business of the estate agent, especially if the data of the estate agent is publicized without him/her having to pay a penny. People will search for real estate in the region where the estate agent works and will find the big site showing the mined data, emphasizing the contact of the estate agent.&lt;/p&gt;
&lt;p&gt;So, to cope with all possible needs of data-source owners, the planner of a data-miner project might want to support listing results with or without details page. Imagine the case when one wants visitors to his/her website and would not like another site to be visited instead. In this case, one can tell him/her that, if he/she allows the extraction of data from his/her site, then they will appear in the list of results, but will not have a details page, instead, when the user clicks on such a result, the website of the owner of the data-source would be opened in a new tab. In this case we are giving them an attractive offer, so that our site will essentially help getting visitors to his/her site. And of course, for those who just want to share the information with as many people as possible, one could show a details page for his/her data. This is a simplified strategy, but illustrates the idea of how people can be convinced to allow us to extract their data.&lt;/p&gt;
&lt;h4 id=&#34;14-the-actual-problem-statement&#34;&gt;1.4. The actual problem statement&lt;/h4&gt;
&lt;p&gt;In this article we intend to have solid ideas of how hierarchical data can be extracted by a thematic data-extractor from data-sources where the owner is content with their data being extracted.&lt;/p&gt;
&lt;h3 id=&#34;2-the-extraction&#34;&gt;2. The extraction&lt;/h3&gt;
&lt;p&gt;Now we have hierarchies to work with, possibly many. Nodes can have the parent-child relation, but they can have the ancestor-descendant relation as well. A is the ancestor and D is its descendant, if A is the parent of D, or we have a sequence of nodes S, where Si is the parent of Si+i for each neighboring pair of the sequence and A is the parent of S1, Sn is the parent of D. Consider this HTML code chunk:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;dimensions&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;large-width&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;area&amp;#34;&lt;/span&gt;&amp;gt;Area&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;dimension-data&amp;#34;&lt;/span&gt;&amp;gt;500&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt;&amp;gt; &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;unit&amp;#34;&lt;/span&gt;&amp;gt;sqm&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;height&amp;#34;&lt;/span&gt;&amp;gt;Height&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;dimension-data&amp;#34;&lt;/span&gt;&amp;gt;60&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt;&amp;gt; &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;unit&amp;#34;&lt;/span&gt;&amp;gt;m&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We see that the div having the class of dimensions is the parent of the div with the large-width class and the ancestor of the spans having the area and height classes, respectively. In the case of hierarchical data, a descendant is inside the ancestor; knowing this gives us a lot of context in many cases.&lt;/p&gt;
&lt;h4 id=&#34;21-semantic-concepts&#34;&gt;2.1. Semantic concepts&lt;/h4&gt;
&lt;p&gt;In hierarchical structures we have some nodes, a (usually small) subset of which contains interesting data for us. For instance, in the example shown at point 2 we have a div which exists to style the shown data, which has some useful information in its descendants, which have the classes of area and height having the class of dimension-data.  However, the div having the class of large-width by itself does not have any useful information outside those descendant nodes, and frankly, it is just a styling node, which makes it irrelevant from our point of view. This means that the large-width div should not exist for us conceptually, we just need to know that we have a concept of dimensions, inside which we should be able to find the area and height. In terms of JavaScript selectors we know that we can find dimensions inside the document and area and height inside it, like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;let&lt;/span&gt; dimensions = [];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;let&lt;/span&gt; dimensionContainers = &lt;span style=&#34;color:#038&#34;&gt;document&lt;/span&gt;.querySelectorAll(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;.dimensions&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;let&lt;/span&gt; dimensionContainer &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;of&lt;/span&gt; dimensionContainers) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; dimension = {};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;let&lt;/span&gt; areaContainer = dimensionContainer.querySelector(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;.area&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (areaContainer) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;let&lt;/span&gt; value = areaContainer.querySelector(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;.dimension-data&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;let&lt;/span&gt; unit = areaContainer.querySelector(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;.unit&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (value &amp;amp;&amp;amp; unit) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            dimension.area = {value: value.innerText, unit: unit.innerText};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;let&lt;/span&gt; heightContainer = dimensionContainer.querySelector(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;.height&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (heightContainer) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;let&lt;/span&gt; value = heightContainer.querySelector(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;.dimension-data&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;let&lt;/span&gt; unit = heightContainer.querySelector(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;.unit&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (value &amp;amp;&amp;amp; unit) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            dimension.unit = {value: value.innerText, unit: unit.innerText};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     dimensions.push(dimension);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We immediately notice some details in the code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It does not deal with large-width at all, because it’s irrelevant, instead, it just focuses on nodes, which are semantically relevant.&lt;/li&gt;
&lt;li&gt;When a concept is found, its direct sub-concept is searched inside its structural context instead of the whole context, so we are particularizing the search.&lt;/li&gt;
&lt;li&gt;Our code smartly searches for plural results in the case of dimensions and is aware that area and height is singular in its parent concept, the dimension.&lt;/li&gt;
&lt;li&gt;The code does not assume the existence of any data.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are also problems to cope with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What happens if the structure changes over time? How can we maintain the code we have above?&lt;/li&gt;
&lt;li&gt;The code above is based on empiric evidence, on the findings of a developer, but this is only proving that the hierarchy the code above is dealing with exists, but it certainly does not prove this is the only structure to work with.&lt;/li&gt;
&lt;li&gt;How can we cope with composite data, like extracting something like “height: 60m”.&lt;/li&gt;
&lt;li&gt;How can we cope with the variance of data, such as synonyms?&lt;/li&gt;
&lt;li&gt;How can we cope with paging where applicable?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All these are serious questions, which show that such a concrete code will not solve the problems we face. We will need abstraction to progress further than the limits of particularity and achieve the level of a thematic data-miner. We have seen that in our examples we had a hierarchy of semantic concepts and also, we can observe the rule that an ancestor concept is an ancestor structurally as well. Also, the algorithm we had above has a pattern of searching for the child concept in the context of the parent concept.&lt;/p&gt;
&lt;p&gt;In reality we also have the problem of conceptual inconsistency, that is, the structure of the same data-source can be varied and in some cases they are at a totally different location in the structure. To give you a practical example, let’s consider the example we had about real-estate properties and their dimensions particularly. It is possible that the height of the real estate makes it very attractive for buyers, so the developers of the data-source decided to show the height separately, in an emphasized manner, at the top of the page and not to show it at its usual place. In this case, if we would not cope with this important detail, we would miss the height for real-estate properties where the height is the most important detail; we would miss the stars of the show.&lt;/p&gt;
&lt;h4 id=&#34;22-semantic-rules&#34;&gt;2.2. Semantic rules&lt;/h4&gt;
&lt;p&gt;In 2.1 we have seen how we can have an understanding about the conceptual essence. Naturally, the concepts are useful by themselves, but we need to build up a powerful structure, a signature of the concepts, which, if shown on a diagram would describe the essence of the structure, the conceptual essence in such a powerful way that one could understand it at a glance (unless there are too many nodes for a human, of course).&lt;/p&gt;
&lt;p&gt;In order to gain the ability to build up such a powerful structure we need to find patterns, but in a more systematic way than the one we have seen in the naive code used as an example. Concepts can be described by rules. I call these rules semantic rules. What attributes describe a concept:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;parent concept(s):&lt;/strong&gt; Which concepts can be the parents of the current concepts? A special case is a root parent. Also, the possibility to define multiple parents is to avoid duplication when the very same concept in the very same substructure can be present at various places.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;descendant(s):&lt;/strong&gt; Useful to make the rule more specific and possibly filter out unneeded cases and thus increase performance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;relative path:&lt;/strong&gt; How can the given concept be found starting from the parent concept as root?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;plurality:&lt;/strong&gt; Should we stop at the first match, or continue searching?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;excludes:&lt;/strong&gt; Which concepts are excluded if this concept is matched? (this is a symmetrical relation)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;implies:&lt;/strong&gt; What concepts imply this concept? (consequently, if this concept is not matched, the concepts which imply it can be excluded as well)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;value:&lt;/strong&gt; Where the actual value of the concept can be found.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If the structure of the data source changes over time, then occasionally the semantic rules will have to change as well. However, arguably in the majority of cases the relative path of the concepts will be the only thing to be changed in this case, which is much easier to maintain than to refactor code. If the relative path descriptor does not change and the virtual structure of our semantic rules remains similar, then our data-miner might just work well even if the data-source is changed.&lt;/p&gt;
&lt;p&gt;For example, in the case of web-crawlers, writing the initial code-base is just a fraction of the long-term costs. The real financial burden is maintaining the crawlability of many thousands of different sites, all changing from time to time. With semantic rules, even if they are defined manually the maintainability is largely simplified. Yet, if we have a module which proposes the new semantic rules, it would not hurt if there are many data-sources.&lt;/p&gt;
&lt;p&gt;Imagine the case when we already have a well-defined set of semantic rules and a cron job detects that some data from a data source was not found in the last few hours, so it would search for the missing data in the data-source and, once found, it would generate the semantic rules for it and propose a new semantic tree of rules, which would run in parallel with the main semantic tree and store data in some experimental place. When the human developers would arrive back and check the reports, they would see that the data-miner thinks that the semantic tree needs to be changed and even has a proposal, also, for the case when the data-miner is right with its proposal, nothing was missed, the extracted data is among the experimental data, but once the new semantic tree is accepted, the experimental data would override the actual data.&lt;/p&gt;
&lt;p&gt;Of course, the engine will not be 100% accurate in such a case, its suggestion might be mistaken, or, even if accurate, slight adjustments might be helpful. A relative path might be less accurate than needed, or the concept in the changed structure might have a different plurality, but even if there is room for improvement, such an automatic feature, generating a new semantic tree would be extremely helpful and would make sure that data is accurately extracted even in the case of large changes.&lt;/p&gt;
&lt;p&gt;If the owner of the data-source is cooperating, then he/she could provide the changed semantic tree.&lt;/p&gt;
&lt;p&gt;The parser is the part of the project which should do the job of handling composite data, but at the level of semantic rules the parser could be helped with a strategy of defining rules. One could define a syntax for the parser, so it would know which concepts are not atomic and maybe even some clues about how should they be parsed.&lt;/p&gt;
&lt;p&gt;Synonyms could be dealt with keyword clusters.&lt;/p&gt;
&lt;p&gt;Navigation can be handled by a module created for this purpose, we can call it the navigation module. The algorithm below describes how data-mining should occur:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;initialNavigation()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;while (page ← page.next())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    for each element in elements
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        for each node in semanticTree  // breadth-first or depth-first traversing
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            if (applicable(node)) then extract(node)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        end for
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    end for
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;end while
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;finalNavigation()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Before we move on to deal with semantic trees we need to solve the problem of conceptual inconsistencies. We have seen that concepts can have multiple conceptual parents, but this is not inconsistent, nor violating the criteria of a tree. In reality for each element a concept will have a single parent, but it is perfectly possible that a given concept will have a parent for an element and a different parent for another element. This is what we described with the possibility of a concept having one of many possible parents/​element. However, even though we have a very good explanation for a concept having more parents, we still have to deal with the possibility of a concept being present twice for the same element. How is this possible?&lt;/p&gt;
&lt;p&gt;Let’s consider the example of books displayed on a website. A book may have main author(s) and secondary author(s). It would not be surprising at all if the main authors are displayed differently than secondary authors. Also, a main picture might be displayed of the book’s cover and maybe some smaller images elsewhere, shown in a gallery. This would be a nice feature on a site which shows children’s books. However, from our perspective this means that the same concept is placed at several places at the same time. One may think of quantum mechanics, where time-place discrepancies are also possible.&lt;/p&gt;
&lt;p&gt;How can we solve this problem for ourselves? We need to have an understanding, otherwise the whole thought process will go astray. My solution is to differentiate the concepts in the different stages of extraction and parsing. This would mean that the concept of “author” or “picture” is conceptually unique when we store it, even though these might be plural. More elements do not necessarily mean more concepts. On the other hand, at the time of extraction, the main picture is a different concept than the other pictures, also, the main authors are a different concept from the secondary authors. The moment of merging happens at the point when we store these and therefore have to convert the extraction concepts into the concepts we store.&lt;/p&gt;
&lt;h4 id=&#34;23-semantic-tree&#34;&gt;2.3. Semantic tree&lt;/h4&gt;
&lt;p&gt;The semantic rules we define have a parent-child and ancestor-descendant relation. The semantic tree is the blueprint of the conceptual essence, a plan to extract data and also, its attributes instruct the extractor about what concept should be found where, how should the extractor operate to have good performance and so on.&lt;/p&gt;
&lt;p&gt;However, the entities to extract can vary greatly and there might be cases when  seemingly the same concept is distributed among various places. The word “seemingly” here means that even though at the end these concepts will be merged, at the phase of the actual data-mining we view these to be similar, but different concepts. The fact that a conceptual node might have several parents in the semantic rules only means that one of the parents of the list is to be expected, which means that all of the listed parents are possible. Consider a semantic rule which says that the parent of currency can be the description or the price:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;parent: description,price&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This means that the parent can be any of the elements of the list, that is, in the case of some elements the parent will be description, but in the case of some other elements, the parent will be price, so we do not violate by design our aim to have a semantic tree.&lt;/p&gt;
&lt;p&gt;We have to watch out for cycles though. Without additional tools there is no protection against cycles, that we might accidentally add while we define the semantic rules, or our semantic rule generator does its magic. However, it makes sense to check whether there is a cycle in the semantic tree. If this is done automatically, then all the better.&lt;/p&gt;
&lt;p&gt;However, since the description of semantic trees can define multiple disjunct parents to cope with the possibility to cope with the actual tree of concepts for all elements, at least those whose pattern is known, the semantic tree in reality is a semantic tree pattern and when we use it or we search for the cycles, we will need to traverse the possible parents where more of them are listed.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2019/03/the-flow-of-hierarchical-data-extraction/SemanticDataExtractorFigure2.png&#34; alt=&#34;&#34; title=&#34;Semantic tree example&#34;&gt;&lt;/p&gt;
&lt;p&gt;Consider the example we have brought for a semantic tree.&lt;/p&gt;
&lt;p&gt;We can see that we have a single main concept, “REAL-ESTATE”. This is not a general pattern, there might be several main concepts to extract on the same data-source, but for the sake of simplicity we have a single one. Implicitly, the technical implementation involves a single, abstract root, which is the parent of all the main concepts. We see that “TYPE” is plural for “REAL-ESTATE”, but “BEDROOM #” is singular. The conceptual reason is that we technically defined type in such a way, that not all pairs of types are mutually exclusive so if a type is found, for example “Bungalow”, the engine should not stop searching for other types, but if the number of bedrooms is found, then there is no point to further search for numbers of bedroom, because it is safe to assume that even if there are several different occurrences of this concept, they will be equivalent.&lt;/p&gt;
&lt;p&gt;Why is “CURRENCY” special? It has two potential parents: “DESCRIPTION” or “PRICE”. In some cases it can be found inside “DESCRIPTION”, in other cases it can be found inside price. For example, if there are several values for “PRICE”, then “CURRENCY” is inside “DESCRIPTION”, but otherwise “CURRENCY” is inside “PRICE”.&lt;/p&gt;
&lt;p&gt;But why could a real-estate property have several different prices? Well, this is outside the scope of data-mining, but to have an understanding, it is good to consider a viable example. Let’s consider the example of an estate agent who has a 20% bonus if he/she successfully sells a given real-estate property within a month. In this case, the agent might want to draw buyers and put a 5% discount on the property for a month and if he/she is successful in selling it, then he/she will still have a nice bonus. Considering this economic mechanism the data-source might be showing the prices in a special way if there is such a discount, like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;table&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;prices&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;tr&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;td&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;price&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt;&amp;gt;100000&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;price red&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt;&amp;gt;90000&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt;&amp;gt; 10% discount!&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;td&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;td&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;currency&amp;#34;&lt;/span&gt;&amp;gt;$&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;td&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;tr&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;table&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- … --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;while, if there is a single price, a different structure is generated:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;price&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt;&amp;gt;100000&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;span&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;currency&amp;#34;&lt;/span&gt;&amp;gt;$&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We notice again that the possibility of multiple parents does not mean that there will be any extracted element with multiple parents, it just describes that among the many elements some of the items will have “PRICE” as parent, the others will have “DESCRIPTION” as parent.&lt;/p&gt;
&lt;p&gt;If we take a look at “DIMENSIONS”, we will see several concepts with the same name (“VALUE” and “UNIT”), but they have a different meaning in their specific context (“AREA” and “HEIGHT”, respectively).&lt;/p&gt;
&lt;p&gt;Another interesting region is “CONTACT”, which has “PERSON” and “COMPANY” elements as conceptual children and both “PERSON” and “CONTACT” is plural. The underlying logic is that several companies or persons can be contacted when one wants to buy/​view a real-estate. We have sub-concepts of “FACEBOOK”, “EMAIL”, “PHONE”, “NAME”, “OTHER” and “WEBSITE” for both “PERSON” and “COMPANY”, but similarly to the example we have seen with “CURRENCY”, here the concepts have different meanings. A corporate website is a different thing from a personal website.&lt;/p&gt;
&lt;p&gt;However, if we draw/​generate such a semantic tree, then it is better than a long documentation. It actually describes for coders the exact way the engine will operate and in the case when the engine is suggesting a new semantic tree for a reason, then, provided that the engine generates the tree’s picture, one will immediately understand what the essence of the engine’s suggestion is. Also, with such a nice diagram managers will understand the mechanism of the system at a glance.&lt;/p&gt;
&lt;h4 id=&#34;24-parallelization&#34;&gt;2.4. Parallelization&lt;/h4&gt;
&lt;p&gt;It is feasible to send parallel requests at the same time, which could happen using promises and the event queue in the case of JavaScript, or multiple threads in a multi-threaded environment.&lt;/p&gt;
&lt;h3 id=&#34;3-symbiosis&#34;&gt;3. Symbiosis&lt;/h3&gt;
&lt;p&gt;If the owner of the data-source is happy and supportive for his/her data to be extracted, then they might notify the maintainers of the data-miner whenever structural changes occur, or he/she can provide an API from which data can be extracted, for example a large JSON. However, this JSON will be probably hierarchical as well.&lt;/p&gt;
&lt;p&gt;In some extremely lucky cases the owner of the data-source will be happy to provide and maintain the semantic rules. This could happen in the case when “spreading the word” via a data-miner is deeply valued by the owner of the data-source. The key is to have an offer, which helps reaching the goals of the data-source, so the owner of the data-source will see the data-miner as his/her extended hand instead of seeing it as a barrier in reaching the goals of the data-source.&lt;/p&gt;
&lt;h3 id=&#34;4-parsing-the-data&#34;&gt;4. Parsing the data&lt;/h3&gt;
&lt;p&gt;At the point when the data was successfully extracted, the results can be parsed just before storing it. For example in some cases we might have textually composite data in the same node, which is impossible to separate via the semantic tree, which needs leaf nodes of the original structure as atoms. So, in many cases a separate layer is needed to decompose composite textual data which holds data applicable to different concepts.&lt;/p&gt;
&lt;p&gt;Also, if, for some technical reasons the semantic tree split a concept into different concepts (for example main authors and secondary authors), then the data-parser can merge the concepts which belong to be together into a single concept. There are many possible jobs the data-parser might fulfill, depending on the actual needs.&lt;/p&gt;
&lt;h3 id=&#34;5-analyzing-the-data&#34;&gt;5. Analyzing the data&lt;/h3&gt;
&lt;p&gt;Let’s assume that we have a very nice schema and we store the data we have efficiently. However, we might be interested to know what patterns can we find in our data. Let’s see what patterns we are interested to find. They include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.vldb.org/conf/1994/P487.PDF&#34;&gt;association rules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://opentextbc.ca/dbdesign01/chapter/chapter-11-functional-dependencies/&#34;&gt;functional dependencies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;conditional functional dependencies (a functional dependency upon the table or cluster records provided a condition is met)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;AR (Association Rule):&lt;/strong&gt; &lt;code&gt;c =&amp;gt; {v1, …, vn}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If a certain condition (c) is fulfilled, then we have a set of constant values for their respective (database table) columns.&lt;/p&gt;
&lt;p&gt;For example, let’s consider the table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;person(id, is_alive, has_right_to_vote, has_valid_passport)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, we can observe that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(is_alive = 0) =&amp;gt; ((has_right_to_vote = 0) ^ (has_valid_passport = 0))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So, this is an association rule, which has the condition of is_alive = 0 (so the person is deceased) and we know for a fact that dead people will not vote and their passport is invalid.&lt;/p&gt;
&lt;p&gt;When we extract data from a source, there might be some association rules (field values are associated to a condition) we do not know about yet. If we find those out, then it will help us a lot. For instance, imagine the case when for whatever reason an insert/​update is attempted with values:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;is_alive = &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;has_right_to_vote = &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this case we can throw an exception, so, this way we can find bugs in the code or mistakes in the semantic tree. This kind of inconsistency prevention is useful even if we are not speaking of data-mining, but, in the context of this article it is extremely useful, as it might detect problems in the semantic tree automatically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FD (Functional Dependency):&lt;/strong&gt; &lt;code&gt;S → D&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The column-set S (Source):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;S = {S1, …, Sm}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;determines the column-set D (Destination):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;D = {D1, …, Dn}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The formula more explicitly looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{S1, …, Sm} → (D1, …, Dn)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This relation means that if we have two different records/​entities with the same source values:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Source1 = Source2 = {s1, …, sm}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;then their destination will match as well:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Destination1 = Destination2 = {d1, …, dn}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Inversely this is not necessarily true. If two records/​entities have the same destination values, then the functional dependency does not require them to have the very same sources.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CFD (Conditional Functional Dependency):&lt;/strong&gt; &lt;code&gt;c =&amp;gt; S → D&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;A CFD is a more generalized term of FD. It adds a condition to the formula, so that the functional dependency’s applicability is only guaranteed if the condition is met. We can describe functional dependencies as particular conditional functional dependencies, where the condition is inherently true:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(true =&amp;gt; S → D) &amp;lt;=&amp;gt; S → D&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Also, an AR can be described as&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;c =&amp;gt; {} → D&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id=&#34;51-the-more-useful-mu-relation&#34;&gt;5.1. The More Useful (MU) relation&lt;/h4&gt;
&lt;p&gt;Let’s consider that we have two patterns, P1 and P2, which could be ARs, FDs or CFDs. Is there a way to determine which of them is more useful? Generally speaking:&lt;/p&gt;
&lt;p&gt;P1 MU P2 if and only if P1 is more general than P2.&lt;/p&gt;
&lt;p&gt;Since both ARs and FDs are particular cases of CFDs, we will work with the formula of CFDs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;P1 = (c1 =&amp;gt; S1 → D1)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;P2 = (c2 =&amp;gt; S2 → D2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;P1 MU P2 &amp;lt;=&amp;gt; ((c2 =&amp;gt; c1) ^ (S1 ⊆ S2) ^ (D1 ⊇ D2))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that MU is reflexive, transitive, antisymmetrical and has a neutral element.&lt;/p&gt;
&lt;p&gt;Reflexive: &lt;code&gt;(c1 =&amp;gt; c1) ^ (S1 ⊆ S1) ^ (D1 ⊇ D1)&lt;/code&gt; is trivially true.&lt;/p&gt;
&lt;p&gt;Transitive:&lt;/p&gt;
&lt;p&gt;Let’s suppose that&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((c2 =&amp;gt; c1) ^ (S1 ⊆ S2) ^ (D1 ⊇ D2))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((c3 =&amp;gt; c2) ^ (S2 ⊆ S3) ^ (D2 ⊇ D3))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;is true. Is&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((c3 =&amp;gt; c1) ^ (S1 ⊆ S3) ^ (D1 ⊇ D3))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;also true?&lt;/p&gt;
&lt;p&gt;Since &lt;code&gt;c3 =&amp;gt; c2 =&amp;gt; c1&lt;/code&gt;, due to the transitivity of the implication relation we know that &lt;code&gt;c3 =&amp;gt; c1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Since &lt;code&gt;S1 ⊆ S2 ⊆ S3&lt;/code&gt;, due to the transitivity of the subset relation we know that &lt;code&gt;S1 ⊆ S3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Since &lt;code&gt;D1 ⊇ D2 ⊇ D3&lt;/code&gt;, due to the transitivity of the superset relation we know that &lt;code&gt;D1 ⊇ D3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The three transitivities together prove that MU is transitive.&lt;/p&gt;
&lt;p&gt;Neutral element (the least useful):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;false =&amp;gt; {} → All columns&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;false =&amp;gt; c&lt;/code&gt; is always true, &lt;code&gt;{}&lt;/code&gt; is the subset of everything else, including itself and all columns is the subset of all combinations of columns, or, in other words, it’s a superset of all its subsets.&lt;/p&gt;
&lt;p&gt;Antisymmetrical:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;If P1 MU P2 and P2 MU P1, then P1 &amp;lt;=&amp;gt; P2.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;P1 MU P2:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((c2 =&amp;gt; c1) ^ (S1 ⊆ S2) ^ (D1 ⊇ D2))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;P2 MU P1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((c1 =&amp;gt; c2) ^ (S2 ⊆ S1) ^ (D2 ⊇ D1))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;P1 MU P2 ^ P2 MU P1 &amp;lt;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((c2 =&amp;gt; c1) ^ (c1 =&amp;gt; c2)) ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((S1 ⊆ S2) ^ (S2 ⊆ S1)) ^
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((D1 ⊇ D2) ^ (D2 ⊇ D1)) &amp;lt;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(c1 &amp;lt;=&amp;gt; c2) ^ (S1 = S2) ^ (D1 = D2) &amp;lt;=&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;P1 &amp;lt;=&amp;gt; P2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;so the relation is antisymmetrical:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;((P1 MU P2) ^ (P2 Mu P1)) &amp;lt;=&amp;gt; (P1 &amp;lt;=&amp;gt; P2)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This means that MU is a poset (partially ordered set) and all the algebra applicable for partially ordered sets in general can be used to analyze MU as well.&lt;/p&gt;
&lt;p&gt;The importance of the MU relation is that we can start searching for such patterns in an ordered manner, starting from the most useful we consider and eventually composing S and decomposing D into less useful relation candidates whenever a candidate for a pattern proved to be false, also, knowing that a pattern seems to be accurate we also know that all less useful patterns seem to be accurate as well. Also, if we know that a pattern is accurate, we know that all less useful patterns are accurate as well. We can start our search from a useful pattern candidate, but not necessarily from the most useful, as, intuitively, it is not very probable that all the columns will invariably have the same value of all records. It would defeat the purpose of storing so many values. This means that defining the most useful &lt;em&gt;possible&lt;/em&gt; patterns would make sense.&lt;/p&gt;
&lt;h4 id=&#34;52-mu-lattice&#34;&gt;5.2. MU Lattice&lt;/h4&gt;
&lt;p&gt;Possible patterns can be represented using a &lt;a href=&#34;http://mathworld.wolfram.com/LatticeTheory.html&#34;&gt;Lattice&lt;/a&gt;, where the root would be the most useful node and the leaf would be the least useful node. We have a join and a meet operation, which are closures.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;P1 join P2 = (c1 v c2) =&amp;gt; (S1 ⋂ S2) → (D1 ⋃ D2)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;P1 meet P2 = (c1 ^ c2) =&amp;gt; (S1 ⋃ S2) → (D1 ⋂ D2)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Of course:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(P1 join P2) MU (P1 meet P2)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Proof:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(c1 ^ c2) =&amp;gt; (c1 v c2) is trivially true and
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(S1 ⋂ S2) ⊆ (S1 ⋃ S2) is trivially true and
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(D1 ⋃ D2) ⊇ (D1 ⋂ D2) is trivially true.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can split the lattice into many different simple lattices, each having its own condition. Since an AR never has source columns, it cannot be less useful than a non AR CFD. Also, since an FD has a condition which is implied by any possible other condition, FDs are never less useful than CFDs with real conditions.&lt;/p&gt;
&lt;h4 id=&#34;53-domain-of-search&#34;&gt;5.3. Domain of search&lt;/h4&gt;
&lt;p&gt;The domain of search can vary. It can be limited to a single table. Or it can be limited to a cluster of tables, related to each other in one-to-one, one-to-many, many-to-one or many-to-many manner. The condition can be considered to be in a simplistic way, checking only the equals operator of some columns, or, it can be complex and considering several columns, even in a cross-table manner, using several possible operators. This depends on the kinds of patterns we intend to find, the cumulative power of resources, the ability of the development team to work out something serious, time, and, yes, money.&lt;/p&gt;
&lt;h4 id=&#34;54-differentiation-between-patterns-and-reality&#34;&gt;5.4. Differentiation between patterns and reality&lt;/h4&gt;
&lt;p&gt;We can have a P pattern, which was automatically found. We only know that there is no counter-example of the pattern P, or, if we have a level of tolerance, we know that there were not as many counter-examples so we would discard the pattern. So, P appears to be true. But is appearance equivalent to the truth in this case? As a matter of fact nature produces infinitely many examples of seemingly impossible occurrences or highly improbable coincidences.&lt;/p&gt;
&lt;p&gt;It is a common fallacy to concentrate on a pattern and due to the improbability of the result being a mere coincidence to exclude the possibility that it was just a coincidence. Indeed, it’s the so-called &lt;a href=&#34;https://www.logicallyfallacious.com/tools/lp/Bo/LogicalFallacies/175/Texas-Sharpshooter-Fallacy&#34;&gt;Texas sharpshooter&lt;/a&gt; fallacy, even though it’s unconscious in our specific case.&lt;/p&gt;
&lt;p&gt;If I have a cube which has 6 sides, each having a number from 1–6 and I toss it 1000 times and the result will always be six, then I will have the natural feeling that something must be not right, I might be divinely favored, or the stars are lining up in my favor, but in this case I&amp;rsquo;m ignoring the fact that there is no connection between the results of the tosses, or, in other words, my experiments are independent from each other. I could calculate that having a result of 6 for 1000 times has a probability of 1 / 6^1000, which is quasi-impossible. Yet, it is only quasi-impossible and not actually impossible.&lt;/p&gt;
&lt;p&gt;If I toss the same cube 1000 times randomly and get a sequence of 1000 numbers, then I could calculate the probability of my random, not special sequence of 1000 elements occuring in the exact same way it occurred. And, surprise, surprise, the result will be exactly equal to 1 / 6^1000, but, if the results of the sequence are varied, I do not feel the results to be special. As a result, having a result of 6 for 1000 tosses is not special at all either.&lt;/p&gt;
&lt;p&gt;There is no mathematical difference between the probability of tossing a cube 1000 times and getting only sixes and tossing a cube 1000 times and getting a specific sequence of 1000 elements you might choose. The probability of the exact same sequences will be exactly the same before I start tossing the cube. The difference between the two sequences is the meaning I, as a person attribute to one of them.&lt;/p&gt;
&lt;p&gt;Also, if I win a lottery, I might think about the probability of my choice of numeric combination being correct and feel that I&amp;rsquo;m especially lucky, but if I calculate the probability of the actual result when I do not win, I will not find any difference in the probability itself. Yet, people tend to calculate the chances of the case when they get lucky, but not to calculate the chances when they are not. The low probability of a given event is only special because we are interested in it, but we can find infinitely many similarly low-​probability events happening all the time, but we are just not interested enough in the majority of such events to analyze it.&lt;/p&gt;
&lt;p&gt;But let’s see this example further. Before I toss the cube 1000 times I do not know the exact sequence I will get in advance. In fact, it is almost impossible to guess it, but I know that whatever the sequence will be, its a priori probability is converging to zero.&lt;/p&gt;
&lt;p&gt;This means that whenever we do not attribute a pattern a meaning, we are inclined to fallaciously not even consider it to be the nature of how things are. Yet, if we attribute a meaning to a pattern, then we might be inclined to fallaciously not understand that it was a mere coincidence if it happens not to be the natural rule of how things are according to our understanding.&lt;/p&gt;
&lt;p&gt;If we find a pattern with a tool, we get enthusiastic and we almost want it to be the nature of things, but we need to be much more severe before we factually accept a pattern. Consider the example of primes. How many primes are there? The answer is simple: infinitely many.&lt;/p&gt;
&lt;p&gt;Proof (reductio ad absurdum):&lt;/p&gt;
&lt;p&gt;Let’s assume that there is a finite n number of primes and there is no other, except them:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;p1, …, pn&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, let’s consider the number:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;N = (p1 * … * pn) + 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We know that N is indivisible with any of p1, …, pn, so there are two cases: N is either a prime or a composite number. If N is a prime, then we found a new prime. Otherwise, if N is composite, then it is divisible by at least a prime which is not among p1, …, pn. So, in either case we find a new prime, therefore there are infinitely many prime numbers.&lt;/p&gt;
&lt;p&gt;How many primes are pair? Exactly one. It is the number 2. Now, if we have a huge set of primes, among which we do not find 2, not knowing that 2 is a prime, we might be inclined to think that primes can only be odd numbers, which is of course wrong. If we pick a prime randomly from the infinitely many primes, the chance that it will be exactly two is extremely small, rather minuscule. However, if a human has to pick a prime number, a human will know only a few primes and 2 is the “first”, so, among the primes 2 is one that has a high chance of being chosen by a human.&lt;/p&gt;
&lt;p&gt;The point of all this contemplation is that if something is very frequent or highly probable, then it is not necessarily true. When we take a look at a pattern, it is good to be very critical about it and think about how that pattern could fail and what the consequences would be if we assume the pattern to be accurate, yet it leaves us in trouble in the most inappropriate time.&lt;/p&gt;
&lt;h4 id=&#34;55-usage-of-factually-validated-patterns&#34;&gt;5.5. Usage of factually validated patterns&lt;/h4&gt;
&lt;p&gt;Now, if we accept a rule to be factually accurate, then we might want to make sure that it is respected. Assuming that&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;c =&amp;gt; S → D&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;is accurate, we also assume that if the condition is met and there is already a record having the source values of s1, …, sm, then, inserting/​updating another record with the same source values, but with different destination values leads to an error. Let’s suppose that we throw an exception when an accepted pattern is to be violated. If many such exceptions are thrown, then we have a problem. What could the problem be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the semantic tree might have wrong/​deprecated rules&lt;/li&gt;
&lt;li&gt;the older records might be broken&lt;/li&gt;
&lt;li&gt;the pattern might be no longer valid, or, it might have been wrongly accepted in the first place&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See? By analyzing the data we can add some features of machine-​learning, so our data-miner will really rule the problem space it is responsible for. Naturally, such patterns can also be used at insertion and update, when we do not get some of the destination values, but we have a pattern from which we can deduce it. Naturally, a tableau of at least the most frequent source values and conditions could come to our help.&lt;/p&gt;
&lt;p&gt;Knowledge is power. Instead of failing gracefully, outside our limits of what we perceive could result in many months-​long gibberish data. But instead of that pain, we could instantly know when a problem appears and, if we have some helping robotic hands — even if they are only virtual — at the end of the day we will be rarely alerted with urgencies. And such patterns deepen our understanding of the data we work with, even if they cannot be accepted as a general rule. With better understanding we will have better ideas. With better ideas we will have better features and performance. With better features and performance we will have more patterns. And with more patterns: we deepen our understanding further.&lt;/p&gt;
&lt;h3 id=&#34;6-the-flow&#34;&gt;6. The flow&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2019/03/the-flow-of-hierarchical-data-extraction/SemanticDataExtractorFigure3.png&#34; alt=&#34;&#34; title=&#34;The flow&#34;&gt;&lt;/p&gt;
&lt;p&gt;This diagram is an idealized representation of the flow. In reality we might have several different cron jobs, we might be working with threads, in asynchronous manner and the parser is invoked much more frequently, not just at the end of the whole extraction, because we do not have infinite resources. All these nuances would complicate the diagram immensely.&lt;/p&gt;

      </content>
    </entry>
  
</feed>
