<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Patrick’s Azure Blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/paelaz/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/paelaz/feed.xml</link>
    <description />
    <lastBuildDate>Tue, 16 Apr 2019 05:22:00 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>No data for you!</title>
      <link>https://docs.microsoft.com/archive/blogs/paelaz/no-data-for-you</link>
      <pubDate>Mon, 28 Aug 2017 10:35:40 GMT</pubDate>
      <dc:creator><![CDATA[Patrick El-Azem]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/paelaz/?p=476</guid>
      <description><![CDATA[Has this happened to you?
- "We need a copy of production data"
- "Why?"
- "For {staging |...]]></description>
      <content:encoded><![CDATA[<h2>Has this happened to you?</h2>
<div>- "We need a copy of production data"
- "Why?"
- "For {staging | testing | baselining | repro-ing | <a href="https://docs.microsoft.com/azure/#pivot=services&amp;panel=analytics" target="_blank">exploring big data on Azure</a> | doing my job }"
- "No."</div>
&nbsp;
<div>

Getting data can be done by taking a snapshot or copy of production data - like a transactional database backup or copying a set of data files - and bringing this data to the needed environment. But production data may contain sensitive information, such as Personally Identifiable Information (PII) or Protected Health Information (PHI). To protect customer privacy and comply with applicable regulations and compliance frameworks, such data is usually stored in secured environments, and subject to access and movement controls.

Such controls may prohibit providing the data - even to internal teams that need "real-world" data.

... Which means the answer to "We need production data" may be a completely justifiable - but very inconvenient - "No".

&nbsp;

</div>
<h2>But we need that data. Now what?</h2>
We need data to move our project ahead. What are some strategies to consider?
<h3>Use public data</h3>
In some cases, data that is structured identically to production data is not needed. Many public data sets (like <a target="_blank" href="https://datausa.io/" rel="noopener noreferrer">these</a> and <a target="_blank" href="https://www.kdnuggets.com/2015/04/awesome-public-datasets-github.html" rel="noopener noreferrer">these</a>) are available for development, testing, and training. The downside, of course, is that public data sets come with a pre-existing structure, so they will not be useful if your work requires your existing data structure, or any control over the data structure.
<h3>Scrub or mask</h3>
To mitigate concerns about inappropriate disclosure of sensitive data, "scrubbing" or "masking" approaches can obscure, alter, or remove sensitive data from copies or snapshots of the data (for example, see <a target="_blank" href="https://blogs.msdn.microsoft.com/paelaz/2017/01/02/sqlddm/" rel="noopener noreferrer">my post on Dynamic Data Masking</a>). The specific approaches vary depending on the nature and sensitivity of the data, ranging from manual, to automated, to using tools like <a target="_blank" href="https://www.delphix.com/platform/secure" rel="noopener noreferrer">Delphix</a>. In general, an understanding of the data - especially which elements are sensitive - is needed, though more sophisticated approaches or tools can infer what parts of the data need protection by looking for patterns like email address, social security or insurance number, and so on.

However, in highly regulated or very risk-averse environments, scrubbing or masking approaches may not be acceptable due to the concern of "what if we miss something, and inappropriate disclosure happens despite our scrubbing or masking measures?". Something as simple as finding (and scrubbing or masking) permutations of personal identifiers in large text fields, for example, can be challenging to automate with very high accuracy across many records.
<h3>Synthesize</h3>
When pre-defined data sets are not suitable, and when scrubbing or masking is not appropriate, we can consider synthetic data. This means artificially generating data that resemble our production data, and can be substituted for it. In this way, there is no risk of inappropriately disclosing sensitive data, since production data is not accessed or copied.

Initially, we need to mimic our production data <em>structure</em>. This is straightforward, as long as production file or database schemas (i.e. structures) are available.

Next, we need to think about how to generate the synthetic data. The right approach to generating synthetic data that is "close enough" to production data could start simple - for example, duplicate the same record thousands of times, perhaps with an auto-incrementing identifier field.

However, we will probably want to adopt a more nuanced approach to data synthesis that emulates, on a field-by-field basis, the <em>characteristics</em> of our production data as closely as possible.

For numeric fields, this may mean generating values in a set that has similar statistics to the production data: for example, a similar mean and standard deviation for normally distributed data, the same min and max for uniformly distributed data, and so on.

We may have fields constrained to one of a specific list of allowable values - in data science, known as a <a target="_blank" href="https://en.wikipedia.org/wiki/Categorical_variable" rel="noopener noreferrer">categorical feature or variable</a> (for example, days of the week, or colors of the rainbow, or other closed sets). We may even want to weight individual values differently, so that one value appears more often than another.

We may also have fields that fall within a specified range - such as dates that fall within a start and an end date - or fields that we want to generate dynamically, perhaps via some sort of code fragment or anonymous function.

The more dynamic, real-world, and closer to production data we want our synthetic data to be, the more effort we will need to invest in analyzing our production data's characteristics and finding ways to emulate these characteristics at scale. There are many ways of doing this; the details will depend on our environment and controls. (<a target="_blank" href="https://docs.microsoft.com/azure/machine-learning/" rel="noopener noreferrer">Azure Machine Learning</a> and <a target="_blank" href="https://azure.microsoft.com/services/data-catalog/" rel="noopener noreferrer">Azure Data Catalog</a> provide excellent data summary statistics.)

&nbsp;
<h2>Generator Tool</h2>
I wrote a file data generator tool for a recent project where a new environment was being architected in Azure. Validation of this environment required system and load testing with real-world (volume and variety) data. Production data was highly sensitive, there was no non-production data available, and implementing scrubbing/masking was not realistic in our timeframe. The synthetic data generated with this tool enabled environment validation - and the project - to continue.

The rest of this post discusses the tool I wrote, what it does, how it does it, how you can use it, and what else is planned for it. I called it the Synthetic Data File Generator (or <strong>sdfg</strong> below) because <code>sdfg</code> is easy to type and because I don't have an MBA in catchy product naming.

&nbsp;
<h2>How can you use sdfg?</h2>
<div>First, let's get off to a quick start. We'll get sdfg onto your machine and ensure it runs. Then, we'll dive deeper into a technical discussion.</div>

&nbsp;
<h2>Quick Start</h2>
<div>
<table style="border: 1px solid black;border-collapse: collapse">
<tbody>
<tr style="border-bottom: 1px solid black">
<td colspan="2" style="padding: 6px;vertical-align: top">You will need a machine running Windows 10 x64, or Windows Server 2016 x64. (Why? See Technical Details, below.)</td>
</tr>
<tr style="border-bottom: 1px solid black">
<td colspan="2" style="padding: 6px;vertical-align: top">Go to <a target="_blank" href="https://github.com/pelazem/syndatafilegen/tree/master/run" rel="noopener noreferrer">https://github.com/pelazem/syndatafilegen/tree/master/run</a> and download <code>sdfg-win10-x64.zip</code>.</td>
</tr>
<tr style="border-bottom: 1px solid black">
<td colspan="2" style="padding: 6px;vertical-align: top">Extract the zip file contents on your machine.</td>
</tr>
<tr style="border-bottom: 1px solid black">
<td colspan="2" style="padding: 6px;vertical-align: top">Open a command prompt in the folder where you extracted the zip file.</td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top;width: 30%">Start by typing just <code>sdfg</code>. You'll see a prompt that you need to specify the path to a runfile.</td>
<td style="padding: 6px;vertical-align: top"><img src="https://msdnshared.blob.core.windows.net/media/2017/08/sdfg01.png" alt="Command prompt shows sdfg run without any arguments, and its output explaining that sdfg should be invoked with a command line argument pointing to a valid runfile." class="size-full wp-image-485 alignnone" style="border: 1px solid dodgerblue;padding: 2px" /></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td colspan="2" style="padding: 6px;vertical-align: top">What is a runfile? Briefly - a runfile contains your instructions that tell sdfg what synthetic data files to generate. See below for a detailed discussion.

The zip file you downloaded includes a <code>/runfiles</code> folder that contains several example runfiles; these are also available at <a target="_blank" href="https://github.com/pelazem/syndatafilegen/tree/master/runfiles" rel="noopener noreferrer">https://github.com/pelazem/syndatafilegen/tree/master/runfiles</a>. We'll start by using one of those.</td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">I used the <code>csv.json</code> runfile, which instructs sdfg to generate comma-separated values (.csv), at hourly increments over 30 days, with 100-200 records per file. As you can see, that took a little over three seconds.</td>
<td style="padding: 6px;vertical-align: top"><img src="https://msdnshared.blob.core.windows.net/media/2017/08/sdfg02.png" alt="Command prompt shows sdfg invoked with a path to a valid runfile, and output showing the elapsed time for sdfg to run." class="size-full wp-image-495 alignnone" style="border: 1px solid dodgerblue;padding: 2px" /></td>
</tr>

<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
File Explorer shows that sdfg generated 744 .csv files. These are small files and a small amount of data, but if you have gotten this far, you have run sdfg and our Quick Start is successful.
<br />
<small>
Optionally, you can run sdfg with the other sample runfiles in the .zip you downloaded. Check the <code>/runfiles</code> folder; at the time of this writing, in addition to <code>csv.json</code>, sdfg also includes <code>arff.json</code> (ARFF is a file format used by the Weka ML tool and supported in Azure ML) and <code>fixedwidth.json</code> generic runfiles.
</small>
</td>
<td style="padding: 6px;vertical-align: top"><img src="https://msdnshared.blob.core.windows.net/media/2017/08/sdfg03.png" alt="File Explorer shows output of running sdfg with sample csv runfile." class="size-full wp-image-495 alignnone" style="border: 1px solid dodgerblue;padding: 2px" /></td>
</tr>

<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">A quick look inside one of the generated .csv files shows, yes, comma-separated data.</td>
<td style="padding: 6px;vertical-align: top"><img src="https://msdnshared.blob.core.windows.net/media/2017/08/sdfg04.png" alt="Header row and first few data rows of a CSV file generated by sdfg" class="size-full wp-image-495 alignnone" style="border: 1px solid dodgerblue;padding: 2px" /></td>
</tr>

</tbody>
</table>
</div>

&nbsp;
<h2>Runfiles</h2>
<div>
Now that we have generated a first set of data files , I'll discuss runfiles: what they are, how they are structured, and how you can create your own for your specific file structures.
<br />
Runfiles are JSON files that describe the synthetic data files to be generated. A runfile contains all the information sdfg needs. (My goal was to enable a zero-code experience, and require only a text editor to customize sdfg output.)
<br />

<div>
<table style="border: 1px solid black;border-collapse: collapse">
<tbody>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top;width: 60%">
sdfg runfiles include the following elements:
<ul>
<li>Generator: instructions for sdfg that are separate from the file structure specifics. Examples include where to write the output, and what date range to use for generated files.</li>
<li>FileSpecs: one or more top-level elements, each of which contains all file-specific details as well as child elements for the fields (e.g. columns in a .csv file) to be written.</li>
<li>FieldSpecs: within each FileSpec, one FieldSpec element for each field to be written.</li>
</ul>
</td>
<td style="padding: 6px;vertical-align: top">
<img src="https://msdnshared.blob.core.windows.net/media/2017/08/sdfg05.png" alt="View of minimal runfile JSON structure showing only top-level elements" class="size-full wp-image-485 alignnone" style="border: 1px solid dodgerblue;padding: 2px" />
</td>
</tr>
</table>
</div>

<br />
&nbsp;
Let's examine runfiles in more detail.
<br />
For reference, please consult <code>/runfiles/TEMPLATE_FULL_RUNFILE.json</code>, which is available both in the .zip download as well as at <a href="https://github.com/pelazem/syndatafilegen/tree/master/runfiles" target="_blank">https://github.com/pelazem/syndatafilegen/tree/master/runfiles</a>. This runfile is a template that includes all supported keys and values, with explanatory comment for each.
<br />
Thus, while I'll discuss several important elements below, please consult this template for details as you build your own runfile. In particular, some elements are constrained to a set of allowable values (for example, which file type you need, such as CSV or fixed-width), and the template runfile documents those.


&nbsp;
<h4>Generator</h4>
<div>
<code>Generator</code> is a top-level element. <code>Generator</code> contains <code>OutputFolderRoot</code> and <code>DateStart</code>/<code>DateEnd</code> child elements.

<code>OutputFolderRoot</code> is a relative or absolute path on the local machine's file system. This is the root folder under which generated files will be written by sdfg.

The dates are used for two purposes: first, if output file paths include date/time tokens (see below), dates from within this range are substituted for the tokens and second, if so specified, dates from within this range are written to the output files as a "when did this record occur" event date/time tracking field.
</div>

&nbsp;
<h4>FileSpecs</h4>
<div>
Runfiles include one or more elements under <code>FileSpecs</code>. This means that a runfile can include instructions to generate multiple file sets. For simplicity, keep it to one FileSpec element at first.

I'll discuss several FileSpec child elements here; others are simple and self-explanatory. See <code>/runfiles/TEMPLATE_FULL_RUNFILE.json</code> for full details.
&nbsp;
<code>FileType</code> is the output file type. Currently, these are supported: <code>arff</code>, <code>avro</code>, <code>delimited</code>, <code>fixedwidth</code>, and <code>json</code>.
&nbsp;
<code>RecordsPerFileMin</code> and <code>RecordsPerFileMax</code> specify a range for how many records should be written to each generated file. The exact number of records will be randomly generated for each file from within this range. (After all, in the "real world", data files don't all have the same exact number of records either.) <small>Need to specify an exact number anyway? Just set both values to your exact record count.</small>
&nbsp;
<code>PathSpec</code> is how you tell sdfg what folder and file names to generate. You can specify an explicit path here (such as "output/myfile.csv"), or you can provide a tokenized value. This tells sdfg to iterate from <code>Generator</code>/<code>DateStart</code> to <code>Generator</code>/<code>DateEnd</code>, and to replace appropriate parts of your <code>PathSpec</code> with the corresponding date/time as it iterates through your date range. Let's illustrate with a couple of examples.
<ul>
<li>
<code>"PathSpec": "{yyyy}\\{MM}\\{dd}\\{hh}{mm}{ss}.txt"</code> will generate output files under a year folder, then a month folder, then a day folder, then a file named for the hour, minute, and second, with a .txt extension. For example: 2017\\07\\18\\145325.txt
</li>
<li>
<code>"PathSpec": "{yyyy}-{MM}-{dd}-{hh}.arff"</code> will generate output files with a filename of year-month-day-hour and a .arff extension. For example: 2017-07-18-14.arff
</li>
<li>
<code>"PathSpec": "{yyyy}\\{MM}\\{yyyy}-{MM}-{dd}-{hh}.csv"</code> will generate output files under a year folder, then a month folder, then a file named for the year, month, day, and hour. For example: 2017\\07\\2017-07-18-14.csv
</li>
</ul>
<small>Notes on PathSpec: as you see, you can use a token (like <code>{yyyy}</code> in the last example) more than once, in both folder and/or file name specification. Also, note the double backslashes (<code>\\</code>): Windows paths use a backslash, but backslash is also the escape character in JavaScript so in a JSON file, I have to use <code>\\</code> to mean <code>\</code>.</small>

&nbsp;
<code>FieldNameForLoopDateTime</code> is the field name to which you would like an event date/time written. This is optional. If you specify it, then as sdfg iterates from <code>Generator</code>/<code>DateStart</code> to <code>Generator</code>/<code>DateEnd</code>, as each record is generated, the "current" date/time within this range is written to it. This is a great way to simulate event log files, which have a strictly increasing event occurrence date/time field on each record.

As <a href="https://github.com/pelazem/syndatafilegen/blob/master/src/SynDataFileGen.Lib/File/FileSpecBase.cs#L120" target="_blank">sdfg iterates through</a> <code>Generator</code>/<code>DateStart</code> - <code>Generator</code>/<code>DateEnd</code>, the incremented loop date/time is adjusted at each iteration with a random coefficient so that successive records are not always incremented by the identical time interval. In other words, a little bit of event interval "jitter" or irregularity is introduced.

<img src="https://msdnshared.blob.core.windows.net/media/2017/08/sdfg12.png" alt="sdfg code fragment showing looping date being adjusted by random factor to simulate event interval irregularity." class="size-full wp-image-485 alignnone" style="border: 1px solid dodgerblue;padding: 2px" />

&nbsp;
<code>Delimiter</code> and <code>Encloser</code> specify strings used to separate (delimit) and enclose, respectively, values in each generated record. These are used only in delimited or fixed-width files. They can be one or more characters long.
Using <code>"Encloser": "\""</code> (note that since this is JSON, I have to escape the double quote symbol, hence the backslash) specifies that each value should be enclosed in double quotes; this is very useful, for example, when generating .csv files with numeric fields that are formatted with a thousands separator which, in some languages/cultures, is a comma.
Enclosing values with commas in double quotes prevents downstream consumers of these files from mistakenly interpreting a thousands separator as a delimiter between fields.
Thus, in this fragment of a .csv record <code>"1000000","2,461","$14,082.50","Wednes...</code>, there are two numeric fields present. The first is 2,461; the enclosing double quotes ensure that this value does not get split into 2 and 461 downstream. Similarly, the enclosing double quotes ensure that $14,082.50 is not split into $14 and 082.50 downstream.

&nbsp;
Three elements are available for fixed-width files.

The first, <code>FixedWidthPaddingChar</code>, specifies what character to use to pad (i.e. fill to the specified width) a field in a fixed-width file where the value is shorter than the field length. For example, if I have a field with a width of 20 characters and I generate a value of "123" for it, sdfg will add 17 of the character specified for <code>FixedWidthPaddingChar</code> so that exactly 20 characters will be written to the field.
The value specified for <code>FixedWidthPaddingChar</code> must be exactly one character long. Typically, this is a space.

<code>FixedWidthAddPadding</code> and <code>FixedWidthTruncate</code> specify where to pad too-short values, and where to cut off too-long values, respectively. Both are constrained to either of two allowable values: "AtStart" or "AtEnd". This lets you control whether too-short values (like in the previous example) are padded out to the field width before or after the value, and whether too-long values are truncated (cut off) at the right or at the left.

&nbsp;
Each <code>FileSpec</code> also contains a list of <code>FieldSpec</code> elements, which are discussed next.
</div>

&nbsp;
<h4>FieldSpecs</h4>
<div>
Each <code>FileSpec</code> element contains a list of <code>FieldSpec</code> child elements. Each <code>FieldSpec</code> element describes how that field should be generated. (In many, but not all, file formats a field is just a column. Because not all file formats are columnar, though, I use the term <em>field</em> rather than <em>column</em> throughout.)

As with <code>FileSpec</code> above, I'll discuss the most important <code>FieldSpec</code> configuration elements below. Again, see <code>/runfiles/TEMPLATE_FULL_RUNFILE.json</code> for full details.

&nbsp;
<code>FieldType</code> designates the type of data that sdfg will generate for this field. Currently, this is limited to one of the following allowable values: <code>Categorical</code>, <code>ContinuousDateTime</code>, <code>ContinuousNumeric</code>, <code>Dynamic</code>, and <code>Idempotent</code>. Let's examine each of these.
<ul>
<li><code>Categorical</code> designates a field whose generated values are randomly selected from a list of allowable values which you specify separately (see <code>Categories</code> below).</li>
<li><code>ContinuousDateTime</code> designates a field whose value will be randomly generated from a min/max range which you specify separately for the field (see <code>DateStart</code> and <code>DateEnd</code> child elements of <code>FieldSpec</code>).</li>
<li><code>ContinuousNumeric</code> designates a field whose value will be a number randomly generated based on the additional configuration you specify, including <code>NumericDistribution</code> and <code>MaxDigitsAfterDecimalPoint</code>.</li>
<li><code>Dynamic</code> designates a field whose value is generated from a C# anonymous function you specify (compiled at runtime using .NET Roslyn) separately in the <code>DynamicFunc</code> element (see below).</li>
<li><code>Idempotent</code> is used in advanced scenarios when you pass in already-existing data programmatically, using sdfg's file format serialization capability without its data-generating capability. See below in this post for discussion of interacting with sdfg's engine programmatically.</li>
</ul>

&nbsp;
<code>EnforceUniqueValues</code> specifies whether sdfg should ensure that, per file, the values generated for the field are unique, i.e. that no values are repeated in this field throughout the file. By default, this is set to false. Setting it to true increases sdfg's memory usage and compute time, so ensure you really need it before setting it to true.

&nbsp;
<code>FormatString</code> is an optional .NET format string. If specified, it will be used to format the generated output. For example: <code>"FormatString": "{0:c}"</code> formats the generated value as a currency; <code>"FormatString": "{0:n0}"</code> formats the generated value as a number with zero digits after the decimal point; and so on. See <a href="https://docs.microsoft.com/en-us/dotnet/standard/base-types/formatting-types" target="_blank">https://docs.microsoft.com/en-us/dotnet/standard/base-types/formatting-types</a> for details on .NET formatting strings.

&nbsp;
<code>PercentChanceEmpty</code> optionally enables sparse data. The default is zero. If set to a value greater than zero, then as each record is generated, in the field where this is specified, there will be that percent chance that the generated value will be empty. This is to enable generation of files that, like the "real world", may have missing data in some records.

I implemented this as a probability per record. So, if you specify 15 here (for 15% chance a given record's value will be "empty"), the final output file will have a percent of empty values in this field that is close to 15, but not necessarily exactly so. This also yields (hopefully) more realistic files where, even if you specify the same value for <code>PercentChanceEmpty</code> on two fields, the generated records will have some records where neither field is empty, some where one but not both is empty, and some where both fields are empty. In other words, I tried to avoid artificially neat generated data.

Since this is specified per field, generated files can be very finely tuned to resemble real data. For example, if production files always have an event date/time and a record ID, but sometimes have empty values in transaction or event fields, this setting enables simulating such a scenario on the applicable fields that sometimes are missing data.

Similarly, <code>EmptyValue</code> enables specification of a string value to be written to the output when the value generated for a record in this field comes up as "empty". By default this is an empty string, but can be set to other values as needed. Again, this is set per field for maximum control over the output.


&nbsp;
<code>FixedWidthLength</code> specifies the size for the field in a fixed-width file. It is ignored in other file types.

&nbsp;
<code>FixedWidthPaddingChar</code>, <code>FixedWidthAddPadding</code>, and <code>FixedWidthTruncate</code> are all optional per field. If specified, they will override the same-named file-level settings. This enables you to optionally format each field in a fixed-width file individually if the file-level defaults are not applicable across all fields in the file. These are ignored for file types other than fixed-width.
&nbsp;
<div>
<table style="border-width: 0;border-collapse: collapse">
<tbody>
<tr>
<td style="padding: 6px;vertical-align: top;width: 35%">
<code>Categories</code> is a list of allowable values for a <code>Categorical</code> field. Optionally, values can be weighted so that some values will appear more often than others in the generated files. Weights are normalized by sdfg during processing, so you can specify any positive values that you like.
<br />
In the screenshot, I provide days of the week as my allowable values. I have weighted the days differently; for example, Friday is weighted 1.0 and Saturday is weighted 0.25, which means Friday is four times as likely to occur in the output as Saturday.
</td>
<td style="padding: 6px;vertical-align: top">
<img src="https://msdnshared.blob.core.windows.net/media/2017/08/sdfg06.png" alt="Runfile fragment shows a field-level Categories element with a list of choices, in this case days of the week, each with a numeric weight." class="size-full wp-image-485 alignnone" style="border: 1px solid dodgerblue;padding: 2px" />
</td>
</tr>
</table>
</div>

&nbsp;
<code>NumericDistribution</code> designates the distribution, and associated parameters, to be used to generate random values for a <code>ContinuousNumeric</code> field.

Currently, the <code>DistributionName</code> is limited to one of these allowable values: <code>Beta</code>, <code>Cauchy</code>, <code>ChiSquare</code>, <code>Exponential</code>, <code>Gamma</code>, <code>Incrementing</code>, <code>InverseGamma</code>, <code>Laplace</code>, <code>LogNormal</code>, <code>Normal</code>, <code>StudentT</code>, <code>Uniform</code>, and <code>Weibull</code>.

Each of the <code>DistributionName</code> values require associated parameters to configure the sdfg random number generator correctly. For example, if you specify <code>"DistributionName": "Normal"</code>, you will also need to specify values for <code>Mean</code> and <code>StandardDeviation</code>. Similarly, if you specify <code>"DistributionName": "Uniform"</code>, you will also need to specify values for <code>Min</code> and <code>Max</code>.

As before, consult <code>/runfiles/TEMPLATE_FULL_RUNFILE.json</code> for details. The numeric distribution element and its child elements are exhaustively documented there, with the parameters required for each distribution clearly designated.

&nbsp;
<code>DynamicFunc</code> is where you provide a C# anonymous function for a <code>Dynamic</code> field. This function will be used to generate a value for this field on each record. Specifically, you need to provide a function that takes no parameters and emits an object.

For example: <code>"DynamicFunc": "() =&gt; System.Guid.NewGuid()"</code> generates a new GUID (globally unique identifier) on each row. What could you do here? You could call a REST API, for example. Note that this function is called <em>for every record</em>, so that a computationally intensive (read: slow) function will significantly increase the time sdfg takes to generate your files.

&nbsp;
<h4>Conclusion</h4>
<div>
This semi-exhaustive look at the internals of sdfg runfiles will hopefully help you build your own runfiles and generate synthetic data files for your specific scenario.
<br />
Next, we'll discuss how you can use sdfg without runfiles.
</div>

</div>

&nbsp;
<h2>Advanced Scenarios</h2>
<div>
Using sdfg with a runfile, as discussed above, is convenient in that it only requires you to edit a JSON runfile in a text editor. This approach works very well to generate standalone files. But what if we need to generate sets of <em>related</em>, differently structured files?

What if one file, for example, needs to use categorical values (i.e. the set of allowable values) which were generated for another file in the set? In this scenario, using sdfg with a runfile will not work, as the runfile approach generates one type of file at a time.

(In future, sdfg may be enhanced to support runfiles that lay out multiple related files, and support the ability to link a <code>Categorical</code> field's <code>Categories</code> list to the output of another <code>FieldSpec</code>. If I get feedback that this is needed at the runfile level - i.e. without needing to dive into code - I will prioritize that feature. In the meantime, let's look at how to do this programmatically with sdfg.)

To continue in this section, it will be very helpful if you've cloned the sdfg github repo (<a href="https://github.com/pelazem/syndatafilegen" target="_blank">https://github.com/pelazem/syndatafilegen</a>) to your machine. You'll need <a href="https://www.visualstudio.com/vs/" target="_blank">Visual Studio 2017</a> (any edition) with the latest update (currently release 15.3) and the <a href="https://www.microsoft.com/net/download/core" target="_blank">.NET Core 2.0 SDK</a> installed.
<div>
<table style="border-width: 0;border-collapse: collapse">
<tbody>
<tr>
<td style="padding: 6px;vertical-align: top;width: 35%">
Opening the solution in Visual Studio, we see the sdfg main projects: <code>SynDataFileGen.App</code> and <code>SynDataFileGen.Lib</code>.
</td>
<td style="padding: 6px;vertical-align: top">
<img src="https://msdnshared.blob.core.windows.net/media/2017/08/sdfg07.png" alt="Visual Studio Solution Explorer shows solution and project structure for sdfg." class="size-full wp-image-485 alignnone" style="border: 1px solid dodgerblue;padding: 2px" />
</td>
</tr>
</table>
</div>
&nbsp;
The <code>CCLF17</code> solution node contains a separate application that programmatically uses the sdfg engine to generate file sets relevant in US health care. Specifically, this application generates file sets in accordance with the Centers for Medicare &amp; Medicaid Services (CMS) Accountable Care Organization - Operational System (ACO-OS) Claim and Claim Line Feed (CCLF) specification for 2017, version 18.0.
&nbsp;
This file set, provided to Accountable Care Organizations (ACOs), typically contains extensive PII and PHI data. ACOs and other organizations processing these files need to accommodate large files containing sensitive data, whose structure can change over time. Load-testing a new processing environment that is not yet security-hardened and compliant is impossible with the real files due to their sensitive content; that was the motivation for writing the CCLF17 application.
&nbsp;

The following screenshot shows an example method (in <code>CCLF17.Lib/CCLFGenerator.cs</code>) which uses sdfg entities (<code>IFieldSpec</code>, <code>FileSpecFixedWidth</code>, <code>Generator</code>, and <code>WriterLocalFile</code>) to first prepare the appropriate field specifications (in a separate helper method), then instantiate a file spec for generating fixed-width files, then instantiating the sdfg Generator with values for the configuration items we discussed above (e.g. output folder, start and end dates) and running it.
&nbsp;

<img src="https://msdnshared.blob.core.windows.net/media/2017/08/sdfg08.png" alt="Code fragment showing invocation of the sdfg core generator from a separate application." class="size-full wp-image-485 alignnone" style="border: 1px solid dodgerblue;padding: 2px" />

&nbsp;
Note that the generator's results - i.e. the records generated for this file - are returned from this method. That's because this CCLF17 application implements the scenario I discussed above, where one file may have <code>Categorical</code> fields whose allowable values are generated for another file. By returning the generated records here, I am enabling code that coordinates between the different files and ensures that one file's generated values serve as the categorical, allowable values for another file.

The next screenshot shows code that calls the method in the previous screenshot, stores its results in an overall list (<code>CCLF1S</code>), then extracts a list of categorical values (<code>CUR_CLM_UNIQ_ID</code>).

<img src="https://msdnshared.blob.core.windows.net/media/2017/08/sdfg09.png" alt="sdfg code fragment that shows extracting a categorical list from the result of calling a generate method." class="size-full wp-image-485 alignnone" style="border: 1px solid dodgerblue;padding: 2px" />

&nbsp;
And finally, the next screenshot shows the categorical value list we extracted in the previous call (and previous screenshot) being passed into the next file generation method, where it will be used as the allowable value list for a categorical field. In this way, we have dynamically generated a list of values for one set of files, then we use those dynamically generated values to constrain related fields in other files.

<img src="https://msdnshared.blob.core.windows.net/media/2017/08/sdfg10.png" alt="sdfg code fragment that shows the categorical value list extracted from the results of a previous file generation call being passed to a subsequent file generation call, to be used as the allowable value list for a categorical field in the new file set." class="size-full wp-image-485 alignnone" style="border: 1px solid dodgerblue;padding: 2px" />


&nbsp;
I won't cover more of the CCLF17 codebase here. Its overall structure is simple; there is extensive code to implement the structural details of the source file set, but it's fairly repetitive and if you are familiar with Visual Studio and .NET development, you'll have no trouble understanding it. Feel free to examine it and contact me with questions or comments.

&nbsp;
In summary, the github repo contains a solution that includes both the core sdfg utility - which outputs the executable we invoked in the Quick Start above - as well as a separate application that interacts with sdfg programmatically to implement a complex scenario that is (currently) not feasible with a JSON runfile.
</div>

&nbsp;
<h2>Performance</h2>
<div>
sdfg's performance will vary based on the specs of the machine you run it on, and how complex you make your runfile (especially that <code>DynamicFunc</code>!).

For a point of reference, I used the sample <code>csv.json</code> runfile for three separate sdfg runs. In each run, I only changed the <code>FileSpec/RecordsPerFileMin</code> and <code>FileSpec/RecordsPerFileMax</code> values; for each run, I multiplied them by a factor of 100X from the previous run.

As you can see in the following screenshot, I used ranges of 100-200; 10,000-20,000; and 1,000,000-2,000,000 records <em>per file</em>. The sample <code>csv.json</code> runfile generates 744 files - one file per hour for 31 days.

Let's examine a few of the results.

On run 2, generating over 11 million total rows took less than 2 minutes; and while run 2's min and max records were scaled 100X compared to run 1, total time to execute scaled by 31X.

On run 3, I generated over <strong>1.1 billion</strong> records in less than 2.5 hours; the generated files added up to 115 GB. Remember: this is with randomly generated data (including a <code>DynamicFunc</code>) on every single record.

<img src="https://msdnshared.blob.core.windows.net/media/2017/08/sdfg11.png" alt="Execution metrics showing various measures for running sdfg against a CSV runfile, with only the min and max rows per file changing between each run." class="size-full wp-image-485 alignnone" style="border: 1px solid dodgerblue;padding: 2px" />

Technical details: these tests were run on a Windows 10 Pro x64 machine, Creators Update (1703), with an Intel Core i7-6700 CPU, 32GB of RAM, and Samsung 850 Evo SATAIII SSD. The machine was otherwise loaded (i.e. not quiesced for max performance), running antimalware and other applications. This was a Release build of sdfg.
</div>


&nbsp;
<h2>Technical Details</h2>
<div>
I wrote sdfg (and the CCLF17 application) as a .NET Core application and a .NET Standard library. Currently, sdfg is at .NET Core/Standard 2.0.

The zip file you downloaded in the Quick Start is named <code>sdfg-win10-x64.zip</code>, and I said you need a Windows 10 x64 or Windows Server 2016 x64 machine to run it. Why the OS and x64 architecture constraint? Because .NET Core gives us the ability to ship the runtime with the application! In the Quick Start, I didn't say your machine needed .NET vAnything, right? That's because the zip file contains all the .NET it needs. Your machine doesn't need to have it installed just to run sdfg.

This is a change from the .NET Framework (currently 4.7), which did require a system-wide installation. Distributing an application built for .NET 4.7 required you to have that .NET framework installed on that machine. By contrast, distributing an application like sdfg as a <a href="https://docs.microsoft.com/dotnet/core/deploying/#self-contained-deployments-scd" target="_blank">self-contained</a> application means you can deploy multiple applications, each potentially built on a different version of .NET Core, without risking negative effects due to a different version of .NET than you built on.

The downside to distributing an application like sdfg self-contained (i.e. shipped with all needed .NET Core files) is that the .NET Core files themselves are OS-specific. Hence, while we gain isolation and safety (no risk of .NET framework version issues), we also have to build <a href="https://docs.microsoft.com/dotnet/core/rid-catalog" target="_blank">per OS and architecture</a>. I provide sdfg for 64-bit versions of Windows 10 and Windows Server 2016; if there is a significant need for another platform, contact me or feel free to clone the repo, add the needed support, and send me a pull request.

To work in the sdfg code after you clone the repo, you will need <a href="https://www.visualstudio.com/vs/" target="_blank">Visual Studio 2017</a> with the latest update (currently 15.3) and the <a href="https://www.microsoft.com/net/download/core" target="_blank">.NET Core 2.0 SDK</a> - not just the runtime - installed.

The <code>DynamicFunc</code> field discussed above enables you to write a C# anonymous function into the JSON runfile, and have it evaluated at runtime using <a href="https://github.com/dotnet/roslyn/wiki/Roslyn%20Overview" target="_blank">Microsoft Roslyn</a> technology. See <a href="https://github.com/pelazem/syndatafilegen/blob/master/src/SynDataFileGen.Lib/Factory.cs#L210" target="_blank">SynDataFileGen.Lib/Factory.cs/GetFunky()</a>.

Currently, sdfg is limited internally to a maximum of 250 million (250,000,000) records per file. If you specify a value for <code>FileSpec/RecordsPerFileMax</code> that exceeds 250,000,000, it will be reset to 250,000,000.
</div>


&nbsp;
<h2>Conclusion and Future</h2>
<div>
I hope the above discussion of scenarios where synthetic data is valuable, and of a synthetic data file generation tool I wrote for such scenarios, is helpful. Please contact me with questions or comments. If sdfg is useful to you, I would greatly appreciate it if you let me know. Similarly, if you clone it and improve the code, please send me a pull request!

What's next for sdfg? A few ideas I am thinking about:
<ul>
<li>Enable runfiles to generate related files with cross-file references to generated values for categorical allowable value lists</li>
<li>Remove the per-file max records limit of 250,000,000</li>
<li>Implement a <code>ContinuousNonNumeric</code> field type to generate random non-numeric values without requiring a <code>DynamicFunc</code> code fragment</code>
<li>Add support for outputting files to other locations than the machine's file system. For example: <a href="https://docs.microsoft.com/azure/storage/" target="_blank">Azure Storage</a></li>
</ul>

Separately: is there a need for a tool like sdfg that "understands" a relational database's schema and generates synthetic data in it, including respecting key relationships? Let me know your thoughts!
&nbsp;
Resources:
The sdfg github repo: <a href="https://github.com/pelazem/syndatafilegen" target="_blank">https://github.com/pelazem/syndatafilegen</a>
</div>
&nbsp;]]></content:encoded>
    </item>
    <item>
      <title>The busy data scientist's walk-through to managing Azure Data Lake Store in R</title>
      <link>https://docs.microsoft.com/archive/blogs/paelaz/r-adls-walkthrough</link>
      <pubDate>Thu, 17 Aug 2017 13:10:09 GMT</pubDate>
      <dc:creator><![CDATA[Patrick El-Azem]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/paelaz/?p=166</guid>
      <description><![CDATA[Earlier this year (2017), my Microsoft colleague Ramkumar Chandrasekaran published a blog post about...]]></description>
      <content:encoded><![CDATA[Earlier this year (2017), my Microsoft colleague Ramkumar Chandrasekaran published a <a target="_blank" href="https://blogs.msdn.microsoft.com/microsoftrservertigerteam/2017/03/14/using-r-to-perform-filesystem-operations-on-azure-data-lake-store/" rel="noopener noreferrer">blog post about performing Azure Data Lake Store (ADLS) file system operations using the R language</a>. After working through that for a recent project, I decided to write a detailed, step-by-step walk-through of getting this running, including the required Azure configuration steps.
<h2>Who is this for?</h2>
<div>

The audience is data scientists comfortable with R and R tools, who need to manage folders and data files in their organization's Azure Data Lake Store but without being Azure experts, requiring tools or languages they're unfamiliar with, or needing administrative access to their organization's Azure environment.

To that end, while several of the steps below can be completed in multiple ways, I have chosen tools or technologies for simplicity (e.g. showing the Azure portal instead of automation scripts). The Resource Links listed at the end of this post include details on alternate ways to complete various steps, as well as code and other resources.

In particular, the walk-through uses Server Principal Name (SPN) authentication, not a user account. This enables authentication and privileges to be customized for least privilege, and to be robust against organizational changes such as a particular user leaving the organization and their credential being disabled.
<h2>Why do this?</h2>
As organizations move to the cloud and undergo change, it's important to maintain productivity. Azure Data Lake is a fantastic platform for big data storage and analysis, but busy data professionals may not yet have the requisite tools or skills to work with new cloud technologies natively. Microsoft's cloud platform enables flexible and hybrid approaches to benefit from new technology while continuing to use existing tools and skillsets, allowing for transition and training at the right pace for people and organizations.

This post was motivated by scenarios where organizations are storing production data in Azure Data Lake, but delivery timelines and operational/resource levels required simple, immediate access to the folders and files there for data analysts and scientists. There are certainly more robust usage scenarios for working with big data in Azure Data Lake; this post is intended to show how to quickly work with the Azure Data Lake file system without requiring clusters or extensive data movement orchestrations.

<em>To be clear</em>: this is <strong>not</strong> a replacement for the analytical power of Azure Data Lake Analytics (ADLA) and U-SQL, or the Hadoop/Spark stack or other big data technologies.

</div>
<h2>What will we accomplish here?</h2>
By the end of this post, we will have completed Azure configuration steps and have a set of operational R scripts that can perform folder and file operations (upload, download, delete, list, rename) in an ADLS account. A data scientist will be able to work in their preferred R environment (such as <a target="_blank" href="https://www.rstudio.com/" rel="noopener noreferrer">R Studio</a> or <a target="_blank" href="https://www.visualstudio.com/" rel="noopener noreferrer">Visual Studio</a> with <a target="_blank" href="https://www.visualstudio.com/vs/rtvs/" rel="noopener noreferrer">R Tools for Visual Studio</a>) and execute various R scripts against ADLS.
<h2>Pre-Requisites</h2>
<div>

To complete this walk-through, you will need an <a target="_blank" href="https://azure.microsoft.com/pricing/purchase-options" rel="noopener noreferrer">Azure subscription</a>. Please ensure you, or someone working with you, can log into Azure before continuing. If you are not in the Owner role for this subscription, you will need to work with someone in that role to complete some Azure steps below.

</div>
<div>
<div>
<table style="border: 1px solid black;border-collapse: collapse">
<tbody>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top;width: 30%">
<div>

To check what role you are in on your Azure subscription, in the Azure portal, click on the left nav menu, then "Subscriptions".

Then click the subscription you will use.

</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-03.png" alt="Locate subscription in Azure portal" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>

When displaying your subscription, click "Access control (IAM)" on the left menu, then consult the blade to see what role you are in.

As you can see here, I am grouping by Role and my account is shown in the "OWNER" group as well as showing "Owner" in the "ROLE" column.

</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-04.png" alt="Confirm your role in the subscription's Access control blade" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
</tbody>
</table>
</div>
<h2>Key Information</h2>
<div>

As you proceed through the following steps, you will need to collect and keep four items of information. Please note them as you encounter them:
<ul>
 	<li>The ADLS account name you create (I use "radls" below)</li>
 	<li>The Azure Active Directory ID</li>
 	<li>The Application ID for the Azure AD application registration you will create</li>
 	<li>A key for the Azure AD application registration you will create</li>
</ul>
<div>As we encounter these items of information below, I will remind you to note them.</div>
<h2>Overview</h2>
<div>

What will we accomplish in this walk-through?
<ol>
 	<li>We'll create an Azure Data Lake Store (ADLS) account in the Azure portal. *</li>
 	<li>We'll create an application and a Server Principal Name (SPN) in Azure Active Directory (Azure AD), also in the Azure portal. *</li>
 	<li>We'll grant the application appropriate permissions to our ADLS account. *</li>
 	<li>We'll apply initial file system permissions in the ADLS account. *</li>
 	<li>We'll install R pre-requisites.</li>
 	<li>We'll write R code to obtain an OAuth2 token, which we need to authenticate (as the SPN) when making calls to the WebHDFS REST API exposed by ADLS.</li>
 	<li>We'll write R code to run various file system operations against ADLS.</li>
</ol>
* These one-time steps require permissions on the Azure subscription. See below for details.

</div>
<h2>1 - Create an Azure Data Lake Store account</h2>
<div>

<small>To complete this step, you will need to be in the Owner role for the Azure subscription you are working in.</small>
<div>
<table style="border: 1px solid black;border-collapse: collapse">
<tbody>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top;width: 35%">
<div>1. After logging into the Azure portal, click "+ New", then "Data + Analytics", then "Data Lake Store / Create".</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-01.png" alt="Create new Azure Data Lake Store account in Azure portal" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>

2. Provide the info needed to provision the ADLS account. (Note the ADLS account name you enter for later use, per "Items to Keep" above.)

I set Encryption Settings to "Not enabled" for simplicity. Please set this to an appropriate value for your environment and data type. See Resource Link #2 for details.

<small>
For testing, I recommend you create a new Resource Group and use it only for Azure resources related to this walk-through. When you are done, it's easy to de-provision the resources created for this walk-through by deleting just the Resource Group created here, which also deletes all resources deployed within it.)
</small>

</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-02.png" alt="Specify ADLS account info" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>

3. Click "Create" and wait for the ADLS account to be created. Then, click into the resource group you specified in the preceding step to see the newly-created ADLS account.

<small>
A new ADLS account's Firewall is <strong>not</strong> enabled by default. If you require Firewall protection, enable it from the ADLS account's "Firewall" blade, and set appropriate firewall rules so that users can later access the ADLS file system.
</small>

</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-05.png" alt="New resource group showing newly created ADLS account" width="767" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<h2>2 - Create a Server Principal</h2>
<div>

<small>To complete this step, you will need to be in the Owner role for the Azure subscription you are working in. If you are not in the Owner role, you may still be able to complete this step: follow the steps at <a target="_blank" href="https://docs.microsoft.com/azure/azure-resource-manager/resource-group-create-service-principal-portal#required-permissions" rel="noopener noreferrer">https://docs.microsoft.com/azure/azure-resource-manager/resource-group-create-service-principal-portal#required-permissions</a> to determine if you have the needed privileges.</small>
<div>
<table style="border: 1px solid black;border-collapse: collapse">
<tbody>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top;width: 35%">
<div>1. In the Azure portal, open the main left nav, click "Azure Active Directory", then click "New application registration".</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-06.png" alt="Create an Azure Active Directory application registration in the Azure portal" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>

2. Enter the info for the application registration, then click "Create".

For "Application type", choose "Web app / API".

For "Sign-on URL", you can enter a non-existent value. This will not be used in our scenario.

</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-07.png" alt="Enter Azure Active Directory application registration information in the Azure portal" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>3. After the application registration is created, find it in the list of applications and click on it.</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-08.png" alt="Newly created Azure Active Directory application registration shown in list in Azure portal" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>

4. On the application's information blade, copy and store the value shown under "Application ID" for later use (per "Key Information" above).

Then, click on "All settings" to open the application's Settings blade (this may already be displayed).

</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-09.png" alt="The Azure Active Directory application's Application ID shown in the Azure portal" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>

5. On the Settings blade, click "Keys". Create a new key by entering a key description and expiration.

After entering these values, click "Save" to display the generated key.

</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-10.png" alt="Create an Azure AD application key in the Azure portal" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>

6. After the key is created, the key value can be copied only once.

Copy and note it for later use (per "Key Information" above) - do this immediately, as you will not be able to re-display this key.

</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-11.png" alt="After creating an Azure AD application key in the Azure portal, the key value can be copied once for later use" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>

7. Next, we also need the Azure Active Directory ID for later use (per "Key Information" above).

Close the App registrations blade. Return to the Azure portal left nav, click "Azure Active Directory" again, then click "Properties" and note the value displayed for "Directory ID".

</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-12.png" alt="Display the Azure Active Directory ID in the Azure portal" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
</tbody>
</table>
</div>
</div>
<h2>3 - Grant ADLS Permissions</h2>
<div>

<small>To complete this step, you will need to be in the Owner role for the Azure subscription you are working in, <em>or at least for the resource group you created above</em> (the subscription owner can add you to the Owner role for the resource group).</small>
<div>
<table style="border: 1px solid black;border-collapse: collapse">
<tbody>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top;width: 35%">
<div>

1. In the Azure portal, navigate to the resource group you created. Click on the ADLS account you created, then click on "Access control (IAM)", then click "+ Add".

We will grant the SPN permissions to just the ADLS account, rather than the containing resource group, to minimize its permission scope.

<small>Instead, you could grant the SPN permissions to the entire resource group; these permissions would then be inherited by all resources in the resource group. This would be useful for other scenarios with the SPN you created. However, I'll restrict the permission scope here and work only with the ADLS account itself.</small>

</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-13.png" alt="Add access control permission to the ADLS account in the Azure portal" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>

2. Enter information for the permission we are creating.

For "Role", specify "Reader". Then, select the name of the Azure AD application you created above; I used "r-adls-app" and have selected that here. Last, click "Save".

<small>
The "Reader" role enables the SPN to <em>see</em> the ADLS resource, but not make any changes to it. Less restrictive roles (such as "Contributor" or "Owner") are not needed for this walk-through.

The permission we are granting here applies to the Azure resource itself, not to the data within it (i.e. the files and folders we will work with; we will grant permissions for those in a later step). By assigning "Reader", we are preventing the SPN from being able to make changes to the Azure resource itself.
</small>

</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-14.png" alt="Enter information for the new permission for the ADLS account in the Azure portal" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>

3. Verify that the permission was created correctly. After the previous step completes, verify that the permission was created correctly in the ADLS account's Access control (IAM) blade.

<small>
Note that I am filtering to Reader roles only, for a more compact display. You may need to click "Refresh" and/or filter to quickly find the appropriate permission.
</small>

</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-15.png" alt="List permissions for the ADLS account in the Azure portal" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
</tbody>
</table>
</div>
</div>

<br />
<h2>Intermission - verify you now have all Key Information</h2>
<div>Before continuing, please consult the "Key Information" list above, and verify that you have copied and set aside all the required pieces of information for later use. Please treat this as sensitive information (especially the application key).</div>
<br />

<h2>4 - ADLS File System Permissions</h2>
<div>
<small>To complete this step, you will need to be in the Owner role for the Azure subscription you are working in, or for the resource group you created above, or at least for the ADLS account itself (the subscription owner can add you to the Owner role for the resource group or the ADLS account).</small>
<div>
<table style="border: 1px solid black;border-collapse: collapse">
<tbody>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top;width: 40%">
<div>

1. Navigate to the ADLS account and select its "Data Explorer" blade. As you will see, in a new ADLS account, no folders or files exist yet.

I created a "/Data/Analysis/" folder structure for this walk-through. Consider a folder structure that makes sense for your scenario, and create it by clicking "New Folder". Navigate through the folder hierarchy you create by using the middle blade.

Next, we will create file system access permissions to permit our SPN to perform all operations <strong>only within the "Analysis" folder - <em>not</em> in its containing "Data" folder</strong>.

<small>This is to show a scenario where a data scientist may not have full access to the root of the ADLS account, and will be constrained to work within a subfolder.</small>

</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-16.png" alt="Use ADLS account Data Explorer blade to view and set file system access in the Azure portal" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>

2. In order for our SPN to access the "Analysis" folder, we have to grant the SPN "RX" (Read and Execute - <em>not</em> Write) permissions at each parent level in the <em>containing</em> folder hierarchy first, so that the SPN can traverse the hierarchy to reach our work folder.

In my scenario, I have to apply appropriate permissions both at the ADLS root, as well as on the "Data" folder. Perform steps 2-4 here on both the root and on "/Data": select the folder, then click "Access". After verifying that the blade subtitle shows that I am at the correct folder (root or "Data (Folder)", shown), I click "+ Add" to open the "Assign Permissions" blade, where I will specify the user or group, and the permissions to grant.

<small>See Resource link 5 for details on ADLS file system access control permissions, and why RX permissions on the containing hierarchy are necessary.</small>

</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-17.png" alt="Create new file system access permission on an ADLS account in the Azure portal" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>

3. In the "Assign Permissions" blade, click on "Select User or Group", then enter the name of the Azure AD application, i.e. the SPN.

In this walk-through, this is "r-adls-app", as we have seen above. Once it is selected, click "Select" to return to the "Assign Permissions" blade.

</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-18.png" alt="Select user for new ADLS file system permission in the Azure portal" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>

4. In the "Assign Permissions" blade, click on "Select Permissions".

Check "Read" and "Execute" Permissions.
Set "Add to:" to "This folder".
Set "Add as:" to "An access permission entry".
Then click "Ok" to save this setting, then "Ok" in the "Assign Permissions" blade to finish saving the new permission.

Remember - this is the <em>enclosing</em> hierarchy. These permissions are the minimal ones required to grant our data scientist full permissions in the <em>contained subfolder</em>. This is why we are not granting Write here, or setting this as a default permission entry.

<small>Remember to perform steps 2-4 both for the root as well as the "/Data" folder!</small>

</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-19.png" alt="Set ADLS containing folder file system permission in the Azure portal" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>

5. Similar to the previous steps, in the "Data Explorer" blade, navigate to the enclosed folder where the data scientist will work. In my scenario, that is the "Analysis" folder (full path: "/Data/Analysis/").

As done in the previous steps, click "Access" and "+ Add" to add a file system permission entry for this folder. Select the same user (the SPN) and continue to "Select Permissions".

Check all Permissions.
Set "Add to:" to "This folder and all children".
Set "Add as:" to "An access permission entry and a default permission entry".
Then click "Ok" to save this setting.
Then click "Ok" in the "Assign Permissions" blade to finish saving the new permission.

This time, we are setting permissions to allow the data scientist - who will authenticate using the SPN - full control in this folder and all folders and files contained within it - but <em>not above it</em>.

</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-20.png" alt="Set ADLS work folder file system permission in the Azure portal" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>

6. Back in the "Data Explorer" blade, ensure you have again selected the enclosed folder where the data scientist will work, then click "Refresh", then "Access".

Verify that the permissions set in the previous step were correctly set and saved.

If the permissions were set and saved correctly, this completes our work in the Azure portal for this walk-through.

</div></td>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-21.png" alt="Verify ADLS folder permissions in the Azure portal" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
</tbody>
</table>
</div>
</div>
<h2>Working in R</h2>
<div>

For the remainder of this walk-through, I will work in <a target="_blank" href="https://www.rstudio.com" rel="noopener noreferrer">R Studio</a>, with <a href="https://docs.microsoft.com/r-server/r-client/what-is-microsoft-r-client" target="_blank">Microsoft R Client</a>. However, please feel free to try this with your preferred R tool or IDE.

Our R code will perform file system operations in our ADLS account by interacting with the WebHDFS API exposed by ADLS. We'll use the HTTR package to make the REST API calls. (Note that I'm using R since this was a specific requirement on the project I mentioned at the top; but any language that can interact with a REST API could be used for this part.) See the Resource Links below for more information on these topics.

I have created a set of R scripts for the work described below. These scripts are available in my public github repo (see Resource Links). Please refer to this repo as I mention R files and scripts below. I recommend you clone the repo, or download the files, so you can work in the code while continuing below.

</div>
<h2>5 - R Pre-Requisites</h2>
<div>

We need one R package to complete this walk-through: HTTR (see Resource Links) and its dependencies.

This is very simple to install:
<pre><code>install.packages("httr", dependencies = TRUE)</code></pre>
I have packaged this in the file <a target="_blank" href="https://raw.githubusercontent.com/pelazem/azure/master/adls-r/1-PreReqs.R" rel="noopener noreferrer">1-PreReqs.R</a> in my github repo. Run this once in your R environment.

</div>
<h2>6 - REST API Authentication</h2>
<div>
<table style="border: 1px solid black;border-collapse: collapse">
<tbody>
<tr>
<td style="padding: 6px;vertical-align: top">
<div>

In order to authenticate to the WebHDFS API using the SPN we created above, we need to obtain an OAuth2 token to send with each API request.

Please edit <a target="_blank" href="https://raw.githubusercontent.com/pelazem/azure/master/adls-r/security_info.R" rel="noopener noreferrer">security_info.R</a>.

</div></td>
</tr>
<tr>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-22.png" alt="Specify security info needed for OAuth2 token generation in R Studio" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>

You will need to fill in the information (from "Key Information", above) as follows:
<ul>
 	<li>For <code>security_adls_account_name</code> replace <code>&lt;your ADLS account name&gt;</code> with the ADLS account name you created above.</li>
 	<li>For <code>security_tenant_id</code> replace <code>&lt;your Azure AD directory ID&gt;</code> with the Azure Active Directory ID you copied above.</li>
 	<li>For <code>security_client_id</code> replace <code>&lt;your Azure AD app ID&gt;</code> with the Azure AD Application ID you created above.</li>
 	<li>For <code>security_client_secret</code> replace <code>&lt;your Azure AD app key&gt;</code> with the Azure AD Application key you generated above.</li>
</ul>
After completing the edits, save and close this file.

</div></td>
</tr>
<tr>
<td style="padding: 6px;vertical-align: top">
<div>

The <a target="_blank" href="https://raw.githubusercontent.com/pelazem/azure/master/adls-r/security_info.R" rel="noopener noreferrer">security_info.R</a> file we just edited is used as a source file by <a target="_blank" href="https://raw.githubusercontent.com/pelazem/azure/master/adls-r/security.R" rel="noopener noreferrer">security.R</a>, which does the actual work of getting an OAuth2 token. This script exposes a <code>security_get_token()</code> function, which is called by the other R scripts we discuss below. This encapsulates all the token work for easy re-use across the various file system scripts.

No edits are needed to <a target="_blank" href="https://raw.githubusercontent.com/pelazem/azure/master/adls-r/security.R" rel="noopener noreferrer">security.R</a>. Feel free to review it to see how it is getting the token and returning it from the <code>security_get_token()</code> function before continuing.

</div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-23.png" alt="Inspect security.R in R Studio" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr>
<td style="padding: 6px;vertical-align: top">
<div>The R scripts provided in my repo for this walk-through follow a consistent structure. Each has these sections, delineated by comments:
<code>### User specified</code>
<code># Security info</code>
<code># Execute</code>
In these files, you only need to perform edits in the section marked by <code>### User specified</code>, for example to substitute in your own folder and file names. In each file, in the <code># Security info</code> section, there is a call to the <code>security_get_token()</code> function in <a target="_blank" href="https://raw.githubusercontent.com/pelazem/azure/master/adls-r/security.R" rel="noopener noreferrer">security.R</a>, used to assemble the authentication header sent to the WebHDFS API in the <code># Execute</code> section. The <code># Security info</code> and <code># Execute</code> sections are functional as is, and do not need editing for this walk-through.</div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-24.png" alt="Review file system R script structure in R Studio" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>Now that we have prepared our <a target="_blank" href="https://raw.githubusercontent.com/pelazem/azure/master/adls-r/security_info.R" rel="noopener noreferrer">security_info.R</a> file with the info we created earlier in this walk-through, and reviewed our <a target="_blank" href="https://raw.githubusercontent.com/pelazem/azure/master/adls-r/security.R" rel="noopener noreferrer">security.R</a> file, we are ready to start working with the ADLS file system from our R environment!</div></td>
</tr>
</tbody>
</table>
</div>
<h2>7 - ADLS file system operations</h2>
<div>
<table style="border: 1px solid black;border-collapse: collapse">
<tbody>
<tr>
<td style="padding: 6px;vertical-align: top">
<div>

We'll start by listing folders in our ADLS file system. Recall that, above, I created a "/Data/Analysis/" hierarchy. If all the previous steps worked correctly, I should now be able to list folders in my ADLS file system.

To do this, I'll run <a target="_blank" href="https://raw.githubusercontent.com/pelazem/azure/master/adls-r/2-ListFolders.R" rel="noopener noreferrer">2-ListFolders.R</a>. Note that on line 6 (see last screenshot in the previous section), I'm setting the folder name whose contents I want to list. Since I'm listing the contents of "/Data", I should see the "Analysis" folder in the results.

</div></td>
</tr>
<tr>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-25.png" alt="Review output of R script to list ADLS folder contents" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>The output shows our "Analysis" directory, so we have successfully queried the ADLS file system!</div></td>
</tr>
<tr>
<td style="padding: 6px;vertical-align: top">
<div>

Now let's upload a file into our "Analysis" folder.

In <a target="_blank" href="https://raw.githubusercontent.com/pelazem/azure/master/adls-r/5-UploadFile.R" rel="noopener noreferrer">5-UploadFile.R</a>, I've specified a file on my local system (d:/test/test1.txt), and a destination path for it in ADLS (/Data/Analysis/test1.txt). Edit these values as needed.

If the upload succeeds, this script should output an HTTP 201 status code at the end, and the file should show up in the ADLS account's Data Explorer display in the Azure portal.

</div></td>
</tr>
<tr>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-26.png" alt="Inspect 5-UploadFile.R in R Studio" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-27.png" alt="Inspect console output, including HTTP status code, after running 5-UploadFile.R in R Studio" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr>
<td style="padding: 6px;vertical-align: top">
<div><img src="https://msdnshared.blob.core.windows.net/media/2017/08/r-adls-28.png" alt="Verify that file uploaded in R Studio using 5-UploadFile.R appears in ADLS Data Explorer in the Azure portal" class="size-full wp-image-176" style="border: 1px solid dodgerblue;padding: 2px" /></div></td>
</tr>
<tr style="border-bottom: 1px solid black">
<td style="padding: 6px;vertical-align: top">
<div>

The R Studio console output shows an HTTP 201 status code, meaning success - the ADLS Data Explorer in the Azure portal shows the file uploaded successfully!

We have now used both our Read and Write permissions to read from, and write to, our ADLS file system.

</div></td>
</tr>
<tr>
<td style="padding: 6px;vertical-align: top">
<div>Please explore the remaining R scripts in the github repo and test them. In particular, <a target="_blank" href="https://raw.githubusercontent.com/pelazem/azure/master/adls-r/8-ReadFile.R" rel="noopener noreferrer">8-ReadFile.R</a> allows files to be downloaded to the local system, so that data scientists can work on source data files in their local environment and with their local tools, as needed.
</div></td>
</tr>
</tbody>
</table>
</div>
<h2>Conclusion</h2>
<div>

In this walk-through, we started with only an Azure subscription. We created an ADLS account and an Azure AD application registration, and configured security for R scripts to run against the ADLS file system by interacting with the WebHDFS REST API.

I hope this walk-through is useful to you. Please contact me with questions or comments - and pull requests are always welcome!

</div>
</div>
<h2>Resource Links</h2>
<div>

For more information on pertinent topics in the walk-through, please refer to these sources:
<ol>
 	<li><span>Ramkumar's post: <a target="_blank" href="https://blogs.msdn.microsoft.com/microsoftrservertigerteam/2017/03/14/using-r-to-perform-filesystem-operations-on-azure-data-lake-store/" rel="noopener noreferrer">https://blogs.msdn.microsoft.com/microsoftrservertigerteam/2017/03/14/using-r-to-perform-filesystem-operations-on-azure-data-lake-store/</a></span></li>
 	<li>Getting started with Azure Data Lake Store: <a target="_blank" href="https://docs.microsoft.com/azure/data-lake-store/data-lake-store-get-started-portal" rel="noopener noreferrer">https://docs.microsoft.com/azure/data-lake-store/data-lake-store-get-started-portal</a></li>
 	<li>Create an Azure AD app and Service Principal: <a target="_blank" href="https://docs.microsoft.com/azure/azure-resource-manager/resource-group-create-service-principal-portal" rel="noopener noreferrer">https://docs.microsoft.com/azure/azure-resource-manager/resource-group-create-service-principal-portal</a></li>
 	<li>Service-to-service authentication, ADLS with Azure AD: <a target="_blank" href="https://docs.microsoft.com/azure/data-lake-store/data-lake-store-authenticate-using-active-directory" rel="noopener noreferrer">https://docs.microsoft.com/azure/data-lake-store/data-lake-store-authenticate-using-active-directory</a></li>
 	<li>ADLS access controls: <a target="_blank" href="https://docs.microsoft.com/azure/data-lake-store/data-lake-store-access-control#common-scenarios-related-to-permissions" rel="noopener noreferrer">https://docs.microsoft.com/azure/data-lake-store/data-lake-store-access-control#common-scenarios-related-to-permissions</a></li>
 	<li>ADLS REST API: <a target="_blank" href="https://docs.microsoft.com/azure/data-lake-store/data-lake-store-get-started-rest-api" rel="noopener noreferrer">https://docs.microsoft.com/azure/data-lake-store/data-lake-store-get-started-rest-api</a></li>
 	<li>Hadoop WebHDFS REST API reference: <a target="_blank" href="https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/WebHDFS.html" rel="noopener noreferrer">https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/WebHDFS.html</a></li>
 	<li>CRAN HTTR reference: <a target="_blank" href="https://cran.r-project.org/web/packages/httr/" rel="noopener noreferrer">https://cran.r-project.org/web/packages/httr/</a></li>
 	<li>My github repo containing the R scripts used in this post: <a target="_blank" href="https://github.com/pelazem/azure/tree/master/adls-r" rel="noopener noreferrer">https://github.com/pelazem/azure/tree/master/adls-r</a></li>
 	<li>The Azure portal: <a target="_blank" href="https://portal.azure.com" rel="noopener noreferrer">https://portal.azure.com</a></li>
</ol>
</div>]]></content:encoded>
    </item>
    <item>
      <title>Azure CDN: overview and dynamic content</title>
      <link>https://docs.microsoft.com/archive/blogs/paelaz/azure-cdn-overview-and-dynamic-content</link>
      <pubDate>Mon, 13 Mar 2017 10:55:39 GMT</pubDate>
      <dc:creator><![CDATA[Patrick El-Azem]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/paelaz/?p=65</guid>
      <description><![CDATA[What is the Azure Content Delivery Network (CDN)?
The Azure CDN offers a global solution for...]]></description>
      <content:encoded><![CDATA[<h2>What is the Azure Content Delivery Network (CDN)?</h2>
The Azure CDN offers a global solution for delivering content to web browsers with minimal latency by caching publicly available assets such as image, CSS, or script files at geo-dispersed edge nodes. Web pages refer to assets (such as image files) by their CDN URLs.

Referring to a relative URL (for example, <code>&lt;img src="/images/logo.png" /&gt;</code>) means the web browser has to download the asset from the source web site. This may not be optimal if the web site is hosted far away from the browser, or if the web server is heavily loaded.

Instead, using a CDN lets asset files be downloaded from edge nodes (dispersed web servers that store copies of the asset files), which both offloads the source web site and shortens the time for web browsers to download files, as there will likely be an edge node closer to the web browser's location than the source web server. This means page load times are reduced, resulting in a more responsive user experience.

<h2>Getting content to the CDN</h2>
How does the CDN get the assets that it distributes to its edge nodes? When setting up a CDN, an endpoint is defined, and an origin must be specified for the endpoint. The endpoint defines the hostname that will be used to refer to assets, and the origin defines the asset source.

For example: let's say I define an endpoint called <code>mycdnendpoint</code>. The hostname for asset retrieval would then be <code>mycdnendpoint.azureedge.net</code> (the <code>azureedge.net</code> top-level domain is fixed for Azure CDN).

Now, I need to define an origin from which the CDN will get assets for the endpoint. In Azure CDN, I can choose from these origin types: Azure blob storage, an Azure cloud service, an Azure web app (this lets me use Azure services exposed as web apps, such as API apps or Azure functions), or any HTTP/HTTPS URL for maximum flexibility.

Choosing Azure blob storage as an origin means it's very simple to expose assets over the CDN: simply load all the assets into the chosen blob storage account (folder structures are fully supported), append the path to the endpoint hostname, and construct a URL.

For example: I have an image called <code>microsoft.png</code> in an <code>assets</code> container (root folder) of the Azure storage account at which I pointed a CDN origin. My CDN URL for this image would be <code>https://mycdnendpoint.azureedge.net/assets/microsoft.png</code>. When any web browser loads a page that includes this image URL, the browser will contact the Azure CDN to download that file, and the CDN will redirect my browser to the CDN edge node that is closest to me to download the file.

Here's a conceptual diagram showing CDN elements, including content sources, CDN origins and endpoints, and public-facing web sites that include CDN-served content.

&nbsp;

[caption id="attachment_165" align="alignleft" width="814"]<img src="https://msdnshared.blob.core.windows.net/media/2017/03/20170311-cdndiagram1.png" alt="Conceptual diagram showing CDN origins, endpoints, and consumption." width="814" height="301" class="size-full wp-image-165" /> <em>Conceptual diagram showing CDN origins, endpoints, and consumption.</em>[/caption]

&nbsp;

I'm leaving out a few details here, such as CDN support for custom domains (i.e. use your own top-level domain name instead of azureedge.net), choosing either or both HTTP and HTTPS, using only a subset of a storage account for CDN assets, using host headers, caching on query string combinations, and more. These beyond-basic capabilities will likely be part of any production-class CDN rollout. Please refer to the <a target="_blank" href="https://docs.microsoft.com/en-us/azure/cdn/cdn-overview">Azure CDN documentation</a> for more details.

<h2>Cache Misses and Hits</h2>
Let's say I just updated my web site with some new pages. These refer to new image files that I just uploaded to my origin blob storage. How do these images get out to all the edge nodes so that visitors to my site see them?

CDNs typically do not pre-load asset files to all the edge nodes. This would require a prohibitive amount of network traffic and edge node storage (after all, each edge node would have to cache every single file in every origin).

Instead, when an asset file is requested from an edge node for the first time, the edge node will check its own file cache. If the asset file isn't there - known as a "cache miss" - the edge node will request the file from the origin, cache it locally, and then return it to the web browser. This means that the first person to request a file will incur a delay similar to requesting it from the source; however, the edge node now has the file, and will keep it cached locally for later visitors, who will get the asset directly from the edge node without going back to the origin, known as a "cache hit".

<h2>Time To Live (TTL)</h2>
How long does the edge node keep the file cached? Typically, a file has a time-to-live (TTL). If a file is not requested by anyone during that TTL, the edge node deletes the file from its cache (but not from the origin, of course). This helps manage edge node resources. <a target="_blank" href="https://docs.microsoft.com/en-us/azure/cdn/cdn-manage-expiration-of-blob-content">TTL is customizable by several methods</a>; if none is set on an asset, Azure CDN defaults to a TTL of seven days.

The appropriate TTL will depend on factors specific to your scenario. For example, your organization's logo presumably does not change very often, but gets downloaded very often as it's on every page of your web site; therefore, consider a longer TTL so that edge nodes don't retrieve this file from the origin more often than is needed.

By contrast, files that change periodically should get shorter TTLs so that your users don't see outdated files (arguably, deploying updated asset files with new file names is a surer way of ensuring your site visitors see the freshest content, but this may not always be practical). There are further considerations to setting the "right" TTL, including balancing network traffic between edge nodes and the origin vs. content freshness; the Azure CDN includes a number of reports (such as cache hit ratio) that can help you tune your TTLs.

&nbsp;

[caption id="attachment_76" align="alignnone" width="725"]<img src="https://msdnshared.blob.core.windows.net/media/2017/03/20170311-cdncachehitratio.png" alt="Azure CDN Cache Hit Ratio metric" width="725" height="172" class="size-full wp-image-76" /> <em>Azure CDN Cache Hit Ratio metric</em>[/caption]

&nbsp;

<h2>Timeline</h2>
What does this look like in reality? The following screenshot shows repeated loads of an image from an Azure CDN endpoint in my web browser's developer tools network timeline.

The first download, labeled as "First load (CDN cache miss)", shows a total time of 650ms. This is because the edge node has to retrieve the file from the origin, which takes longer.

Later loads, labeled as "Later loads (CDN cache hits)", have much shorter total times, between 16 and 49ms. This indicates that the CDN edge node now has the file in its cache and doesn't need to go back to the origin to get it. (Note on the screenshot that I have disabled my browser's local cache, so that the CDN's cache effect is obvious.)

&nbsp;

[caption id="attachment_75" align="alignnone" width="776"]<img src="https://msdnshared.blob.core.windows.net/media/2017/03/20170311-cdntimeline.png" alt="Asset first and later loads from CDN edge" width="776" height="461" class="size-full wp-image-75" /> <em>Asset first and later loads from CDN edge</em>[/caption]

&nbsp;

<h2>New content to CDN immediately</h2>
So far, we have discussed straightforward CDN provisioning from an origin with a relatively stable set of asset files, presumably deployed when a site updates or on another relatively predictable interval - possibly even a continuous deployment process in an ALM solution like <a target="_blank" href="https://www.visualstudio.com/team-services/">Visual Studio Team Services</a>.

But what about scenarios when content is generated dynamically, for example in a browser-based image editing tool, and that content needs to be <em>immediately</em> available through a CDN?

Clearly, waiting for a manual upload or publish process, or a periodic continuous deployment process, would not be suitable due to the delay between asset generation and CDN origin availability. In such a scenario, we need to get the newly created asset file into the CDN origin right away, ideally as soon as it is created.

<h3>File-based content</h3>
Azure blob storage is ideal as an origin for static files. When a file is generated by some sort of process and needs to be CDN-available right away, we can write the file to our Azure storage programmatically as soon as it's created. There are <a target="_blank" href="https://azure.microsoft.com/downloads/">Azure SDKs in various languages and stacks</a>.

Uploading a file to Azure blob storage and setting its TTL is straightforward using the Azure storage SDK. The following screenshot shows the pertinent code; I'm using C# but again, there are SDKs in various languages. Please see the Resources section at the end of this post for a link to the full code base.

On lines 142-143 I'm creating a blob reference for the file I'll upload and setting its content type (this is a MIME type designation; for an image file like a .png or .jpg, the content type would be <code>image/png</code>). Setting the content type here ensures that it propagates to the edge nodes and lets them serve the content up correctly to web browsers.

On line 146, I'm setting a retry policy. This is optional, but good practice; it instructs the Azure blob storage client I'm using to upload my file what to do in case the upload is interrupted. Here, I'm telling it to wait five seconds, then retry up to a max of five times. Guarding against transient failures is a highly recommended best practice in cloud application development.

On line 149, I am <a target="_blank" href="https://msdn.microsoft.com/en-us/library/mt674882.aspx">asynchronously</a> uploading the file to my blob storage account.

On line 152, I set the blob's CacheControl property; this is what CDN edge nodes will use for the file's TTL in their cache. The TTL value is an integer and is measured in seconds.

On line 155, I'm updating the file's properties with the TTL. Then, on line 157 I get its URI in Azure blob storage - this is not a CDN URI yet, but I'm retrieving it so I can first check that it uploaded successfully to blob storage.

&nbsp;

[caption id="attachment_95" align="alignleft" width="902"]<img src="https://msdnshared.blob.core.windows.net/media/2017/03/20170311-uploadblob2.png" alt="C#: upload file to blob storage , get URI." width="902" height="261" class="size-full wp-image-95" /> <em>C#: upload file to blob storage , get URI.</em>[/caption]

&nbsp;

The blob storage location to which I uploaded this file is the origin for my CDN endpoint, so at this point the file should be available not only through its direct storage URI (which I retrieved on line 157, above) but also through CDN URLs. To confirm this, I use an <code>IsBrowsable()</code> method to check that the file I uploaded is available directly from its Azure storage URI as well as through my CDN. Note that I confirm both HTTP and HTTPS CDN URLs - having both available is useful to avoid browser warning messages and lets web developers avoid hard-coding the URL scheme.

&nbsp;

[caption id="attachment_115" align="alignleft" width="888"]<img src="https://msdnshared.blob.core.windows.net/media/2017/03/20170311-checkuris.png" alt="C#: check blob storage and CDN URIs for uploaded file." width="888" height="229" class="size-full wp-image-115" /> <em>C#: check blob storage and CDN URIs for uploaded file.</em>[/caption]

&nbsp;

[caption id="attachment_125" align="alignleft" width="923"]<img src="https://msdnshared.blob.core.windows.net/media/2017/03/20170311-isbrowsable.png" alt="C#: IsBrowsable() method to check whether a URL is available" width="923" height="199" class="size-full wp-image-125" /> <em>C#: IsBrowsable() method to check whether a URL is available</em>[/caption]

&nbsp;

The preceding code fragment (see Resources at the bottom of this post for a link to the complete code) shows a file being uploaded to a blob storage account that is used as a CDN origin, with nothing else that needs to be done to make the file available through the CDN. So this is a very straightforward way to generate files and immediately expose them through the Azure CDN.

<h3>Stream-based content</h3>
Sometimes we may need to serve content that isn't easily persistable as a file in a storage repository; for example, we may need to return a content stream. In the following code fragment, I have a REST API method that instantiates a content stream and writes it to the HTTP response's content property. The method also sets the TTL on the HTTP response using the CacheControl header property; here, I'm setting the TTL to 10 minutes (600 seconds).

&nbsp;

[caption id="attachment_135" align="alignleft" width="996"]<img src="https://msdnshared.blob.core.windows.net/media/2017/03/20170311-apistreamresponse.png" alt="C#: API method HTTP response with stream content" width="996" height="233" class="size-full wp-image-135" /> <em>C#: API method HTTP response with stream content</em>[/caption]

&nbsp;

A REST API that returns content streams lets us use an Azure CDN endpoint that points at the API, rather than at a static storage location. Using an API lets us accommodate a very wide variety of dynamic content-generation scenarios, including varying by parameters or query string, geography, time of day, and more.

Using an API URL like <code>https://<em>mycdnapiendpoint</em>.azureedge.net/api/content/i3</code> (see Resources at the bottom of this post for a link to the full code for this API app), we can again see the pattern of first load being slower than subsequent load as the CDN edge node first has a cache miss, retrieves the content from the origin, and then on subsequent requests has a cache hit.

&nbsp;

[caption id="attachment_145" align="alignleft" width="664"]<img src="https://msdnshared.blob.core.windows.net/media/2017/03/20170311-cdntimelineforapi1.png" alt="CDN API URL first and later loads" width="664" height="218" class="size-full wp-image-145" /> <em>CDN API URL first and later loads</em>[/caption]

&nbsp;

<h2>Conclusion</h2>
The Azure CDN is an excellent way to offload your web application of serving static content. It offers lots of advanced features, a global footprint, and supports multiple endpoint types to accommodate static and dynamic content scenarios.

<h2>Resources</h2>

These are, respectively, links to apps that upload files to Azure blob storage and check immediate CDN availability (Storage Origin App), and a REST API app that returns a content stream based on an ID parameter. Please note <a href="https://bitbucket.org/pelazem/public" target="_blank">the disclaimer here</a>, and feel free to reach out to me with any questions.

<ol>
<li><a href="https://bitbucket.org/pelazem/public/src/adf38b6f101e3584bdd4dca314464f99e268f653/pocs/CDN-BlobAndAPI/OriginStorage/?at=master" target="_blank">Storage Origin App/Lib</a></li>
<li><a href="https://bitbucket.org/pelazem/public/src/adf38b6f101e3584bdd4dca314464f99e268f653/pocs/CDN-BlobAndAPI/OriginApi/?at=master" target="_blank">API Origin App</a></li>
</ol>

]]></content:encoded>
    </item>
    <item>
      <title>Get started with Dynamic Data Masking in SQL Server 2016 and Azure SQL DB</title>
      <link>https://docs.microsoft.com/archive/blogs/paelaz/sqlddm</link>
      <pubDate>Mon, 02 Jan 2017 16:40:11 GMT</pubDate>
      <dc:creator><![CDATA[Patrick El-Azem]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/paelaz/?p=25</guid>
      <description><![CDATA[Dynamic Data Masking (DDM) is a new security feature in Microsoft SQL Server 2016 and Azure SQL DB....]]></description>
      <content:encoded><![CDATA[Dynamic Data Masking (DDM) is a new security feature in Microsoft SQL Server 2016 and Azure SQL DB. The main documentation is <a target="_blank" href="https://msdn.microsoft.com/library/mt130841.aspx">here</a> (also see link under Resources at end). This post is a quick how-to intro to DDM, including applying it in a database and managing which principals see masked or unmasked data. I'll also answer a few questions that commonly come up.
<h3>What is DDM?</h3>
Picture this scenario. You have a database table which stores sensitive data, such as social security numbers, in the clear (unencrypted). Anyone with appropriate access can run <code>select *</code> against this table and see all the sensitive data.

This becomes a concern in organizations where production data is periodically restored into development, test, and/or staging environments. Developers, testers, and other people need to work with the data, but have visibility to sensitive data. This is clearly concerning (and may be unlawful in some jurisdictions). How do we give these roles the data they need, while protecting sensitive data?

This is what DDM does. A database administrator applies a masking rule to a column. The result is that when developers, testers, and other non-administrators run queries against the table, they no longer see masked columns' data in the clear; instead, they see the data in obscured format.

This does <em>not</em> mean the underlying data is now stored encrypted. No - it's still stored in the clear, and any role with UNMASK privilege can still access the data in the clear. DDM is simply a way to obscure sensitive data from roles or users who should not see it in the clear.
<h3>DDM in action</h3>
Let's say you have a table with social security numbers. A <code>select *</code> returns this:

<img src="https://msdnshared.blob.core.windows.net/media/2017/01/img01.png" alt="Sample data" width="125" height="236" class="alignnone size-full wp-image-35" />

We want to use DDM to obscure this data. How do we do that? Simple. We use familiar <code>alter column</code> syntax to designate a column as masked, and we specify how to mask it. Here's how we'd mask the SSN column in T-SQL:<code>
</code>

<code>alter table data.Users
alter column [SSN] add masked with (function = 'partial(0,"XXX-XX-",4)');</code>

What's happening here? First, we're designating the <code>[SSN]</code> column as masked (<code>add masked</code>), then we're specifying how to mask it, using a masking function. Currently, <a target="_blank" href="https://msdn.microsoft.com/library/mt130841.aspx#Defining a Dynamic Data Mask">four masking functions are available</a>; I'm using <code>partial()</code>, which lets me specify how many characters to leave clear at the start, what string to substitute in the middle, and how many characters to leave clear at the end.

After applying this mask, the same <code>select *</code> returns this:

<img src="https://msdnshared.blob.core.windows.net/media/2017/01/img02.png" alt="Sample data masked" width="131" height="232" class="alignnone size-full wp-image-36" />

Note how the SSN data is now masked. Per our masking function, no characters are clear at the start; the data is partly replaced by the mask we specified; and the last four characters are in the clear.

How do we remove masking from a column? Simple:

<code>alter table data.Users
alter column [SSN] drop masked;
</code>

Note that DDM works in T-SQL for both SQL Server 2016 and Azure SQL DB. However, for Azure SQL DB, <a target="_blank" href="https://docs.microsoft.com/en-us/azure/sql-database/sql-database-dynamic-data-masking-get-started">DDM can also be configured using the Azure portal</a>.
<h3>DDM Security</h3>
By default, all principals not in the db_owner role will see masked data; principals in db_owner are automatically granted UNMASK privilege and will see data unmasked (in the clear) regardless of any masking rules applied.

DDM does not prevent masked users from executing DML statements. For example, if they have DELETE privilege, they can delete records from a table with a masked column; similarly with UPDATE. This is expected.
<h3>DDM FAQ</h3>
<em>Why would we use DDM if it doesn't even encrypt the underlying data?</em>

Because in many scenarios, such as dev and test environments, masking is enough protection without the performance and administrative overhead of encryption. For example, daily restores from production to a staging database used for manual and/or automated tests where it's important to understand the underlying data.

In any case, SQL Server offers excellent encryption options. DDM is a great option when masking is enough.

<hr />

<em>"We have some people who need to see masked data in the clear. Does that mean we have to add them to db_owner? We'd prefer not to."</em>

No, people do NOT need to be added to db_owner to see data in the clear. Specific roles or users can be granted UNMASK; currently, this is at a database level, i.e. not to a specific table or column.

Here's how to do this for an OpsMgrRole database role:
<code>grant unmask to [OpsMgrRole];</code>

<hr />

<em>What if someone selects masked data into a temp table, or backs up the database and restores it on another machine? Can they get around DDM on the source table this way?</em>

Short answer: No.
Longer answer: When a user to whom masking applies selects into another table or backs up the database, DDM will write the masked data statically, i.e. in this instance, the written data is no longer "in the clear"; what is written is statically masked. Let's prove it with this T-SQL:

<img src="https://msdnshared.blob.core.windows.net/media/2017/01/img03.png" alt="T-SQL showing that DDM cannot be circumvented using a temp table" width="723" height="473" class="alignnone wp-image-45 size-full" />

What's happening here?

On line 4, I'm reverting to my logged-in user (which happens to be a db_owner member). This is to make sure I am not in the context of a less-privileged user.

On line 7, I'm impersonating a lesser-privileged user who is not a member of db_owner, and who has not been granted UNMASK.

On line 10, I'm creating a temp table. On line 13, I'm extracting data from the source table, which has a mask on the SSN column, into my unmasked temp table. By doing this, I'm trying to get around the mask on the source table.

On line 16, I'm preparing to see people's sensitive data... only to be disappointed - the data is still masked! In fact, the data was written to the temp table statically masked, i.e. it's no longer in the clear in the temp table - it was written with all the X mask characters.

On line 19, I'm reverting back to my logged-in user, who is a db_owner member.

On line 22, I'm selecting data from that temp table again, but (as expected) it's still masked. Remember - it was written to the temp table statically masked by a user subject to masking on the source table, so my db_owner membership and implicit UNMASK privilege do not help.

Last, on line 25 I query the source table and see the data unmasked, exactly as expected, which demonstrates that the source table is dynamically masked whereas the temp table, as expected, is statically masked.

The three result sets from lines 16, 22, and 25 in the above T-SQL:

<img src="https://msdnshared.blob.core.windows.net/media/2017/01/img04.png" alt="img04" width="167" height="431" class="alignnone wp-image-55 size-full" />

Note: the above T-SQL is a screenshot image. I used that for easier readability with color and line numbers. See Resources below to get all the code I used for this post.

<hr />

<em>Will DDM interfere with query execution plans?</em>

No. Queries are executed first, then the results are masked. Nothing changes with regard to query execution plans.

<hr />

<em>We have a more complex situation that's not covered by the currently available masking functions. For example, we have variable-length fields that store people's comments and notes. Can we detect, and mask, social security numbers or credit card numbers within such text blocks, but not mask anything else?</em>

So something more like a regular expression. That's not possible at this point with DDM, but the SQL product group has gotten this feedback.
<h3>Resources</h3>
DDM MSDN documentation: <a target="_blank" href="https://msdn.microsoft.com/library/mt130841.aspx">https://msdn.microsoft.com/library/mt130841.aspx</a>

My code used for this post is in my <a target="_blank" href="https://bitbucket.org/pelazem/public/src/7574ff156cb17761c6498fca9b40156144c8d06a/sql/Security/?at=master">public git repo</a> (please first note disclaimers at the <a target="_blank" href="https://bitbucket.org/pelazem/public">repo root</a> - this is sample code, use at your own risk). The readme for these files contains details, but briefly, I provide you code to create a sample database and then implement and test DDM, including the DDM subvert fragment above. All you need is a SQL Server 2016 test instance.

Hope this helps you get started with Dynamic Data Masking.]]></content:encoded>
    </item>
  </channel>
</rss>