blob: 1a6a45d834fde988e852603f4f9410fcd6869c88 [file] [log] [blame]
<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSON Formatter - Apache Apex Malhar Documentation</title>
<link rel="shortcut icon" href="../../favicon.ico">
<link href='https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="../../css/theme.css" type="text/css" />
<link rel="stylesheet" href="../../css/theme_extra.css" type="text/css" />
<link rel="stylesheet" href="../../css/highlight.css">
<script>
// Current page data
var mkdocs_page_name = "JSON Formatter";
var mkdocs_page_input_path = "operators/jsonFormatter.md";
var mkdocs_page_url = "/operators/jsonFormatter/";
</script>
<script src="../../js/jquery-2.1.1.min.js"></script>
<script src="../../js/modernizr-2.8.3.min.js"></script>
<script type="text/javascript" src="../../js/highlight.pack.js"></script>
<script src="../../js/theme.js"></script>
</head>
<body class="wy-body-for-nav" role="document">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
<div class="wy-side-nav-search">
<a href="../.." class="icon icon-home"> Apache Apex Malhar Documentation</a>
<div role="search">
<form id ="rtd-search-form" class="wy-form" action="../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" />
</form>
</div>
</div>
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
<ul class="current">
<li>
<li class="toctree-l1 ">
<a class="" href="../..">Apache Apex Malhar</a>
</li>
<li>
<li>
<ul class="subnav">
<li><span>APIs</span></li>
<li class="toctree-l1 ">
<a class="" href="../../apis/calcite/">SQL</a>
</li>
</ul>
<li>
<li>
<ul class="subnav">
<li><span>Operators</span></li>
<li class="toctree-l1 ">
<a class="" href="../block_reader/">Block Reader</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../csvformatter/">CSV Formatter</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../csvParserOperator/">CSV Parser</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../deduper/">Deduper</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../enricher/">Enricher</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../fsInputOperator/">File Input</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../file_output/">File Output</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../file_splitter/">File Splitter</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../filter/">Filter</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../fixedWidthParserOperator/">Fixed Width Parser</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../ftpInputOperator/">FTP Input Operator</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../AbstractJdbcTransactionableOutputOperator/">Jdbc Output Operator</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../jdbcPollInputOperator/">JDBC Poller Input</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../jmsInputOperator/">JMS Input</a>
</li>
<li class="toctree-l1 current">
<a class="current" href="./">JSON Formatter</a>
<ul>
<li class="toctree-l3"><a href="#json-formatter">Json Formatter</a></li>
<li><a class="toctree-l4" href="#operator-objective">Operator Objective</a></li>
<li><a class="toctree-l4" href="#class-diagram">Class Diagram</a></li>
<li><a class="toctree-l4" href="#operator-information">Operator Information</a></li>
<li><a class="toctree-l4" href="#properties-attributes-and-ports">Properties, Attributes and Ports</a></li>
<li><a class="toctree-l4" href="#partitioning">Partitioning</a></li>
<li><a class="toctree-l4" href="#example">Example</a></li>
<li><a class="toctree-l4" href="#advance-features">Advance Features</a></li>
</ul>
</li>
<li class="toctree-l1 ">
<a class="" href="../jsonParser/">JSON Parser</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../kafkaInputOperator/">Kafka Input</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../regexparser/">Regex Parser</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../s3outputmodule/">S3 Output Module</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../transform/">Transformer</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../windowedOperator/">Windowed Operator</a>
</li>
<li class="toctree-l1 ">
<a class="" href="../xmlParserOperator/">XML Parser</a>
</li>
</ul>
<li>
</ul>
</div>
&nbsp;
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
<nav class="wy-nav-top" role="navigation" aria-label="top navigation">
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../..">Apache Apex Malhar Documentation</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li><a href="../..">Docs</a> &raquo;</li>
<li>Operators &raquo;</li>
<li>JSON Formatter</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main">
<div class="section">
<h1 id="json-formatter">Json Formatter</h1>
<h2 id="operator-objective">Operator Objective</h2>
<p>Purpose of JsonFormatter is to consume Plain Old Java Object ("POJO") and write them as JSON.
Json Formatter is <strong>idempotent</strong>, <strong>fault-tolerance</strong> &amp; <strong>statically/dynamically partitionable</strong>.</p>
<h2 id="class-diagram">Class Diagram</h2>
<p><img alt="JsonFormatter" src="../images/jsonFormatter/JsonFormatter.png" /></p>
<h2 id="operator-information">Operator Information</h2>
<ol>
<li>Operator location:<strong>_malhar-library</strong></li>
<li>Available since:<strong><em>3.2.0</em></strong></li>
<li>Operator state:<strong><em>Evolving</em></strong></li>
<li>Java Package:<a href="https://github.com/apache/apex-malhar/blob/master/library/src/main/java/com/datatorrent/lib/formatter/JsonFormatter.java">com.datatorrent.lib.formatter.JsonFormatter</a></li>
</ol>
<h2 id="properties-attributes-and-ports">Properties, Attributes and Ports</h2>
<h3 id="platform-attributes-that-influences-operator-behavior">Platform Attributes that influences operator behavior</h3>
<table>
<thead>
<tr>
<th><strong>Attribute</strong></th>
<th><strong>Description</strong></th>
<th><strong>Type</strong></th>
<th><strong>Mandatory</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><em>in.TUPLE_CLASS</em></td>
<td>TUPLE_CLASS attribute on input port which tells operator the class of incoming POJO</td>
<td>Class or FQCN</td>
<td>Yes</td>
</tr>
</tbody>
</table>
<h3 id="ports">Ports</h3>
<table>
<thead>
<tr>
<th><strong>Port</strong></th>
<th><strong>Description</strong></th>
<th><strong>Type</strong></th>
<th><strong>Mandatory</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><em>in</em></td>
<td>Tuples that needs to be formatted are recieved on this port</td>
<td>Object (POJO)</td>
<td>Yes</td>
</tr>
<tr>
<td><em>out</em></td>
<td>Valid Tuples that are emitted as JSON</td>
<td>String</td>
<td>No</td>
</tr>
<tr>
<td><em>err</em></td>
<td>Invalid Tuples are emitted on this port</td>
<td>Object</td>
<td>No</td>
</tr>
</tbody>
</table>
<h2 id="partitioning">Partitioning</h2>
<p>JSON Formatter is both statically and dynamically partitionable.</p>
<h3 id="static-partitioning">Static Partitioning</h3>
<p>This can be achieved in 2 ways</p>
<ol>
<li>Specifying the partitioner and number of partitions in the populateDAG() method</li>
</ol>
<pre><code class="java">JsonFormatter jsonFormatter = dag.addOperator(&quot;jsonFormatter&quot;, JsonFormatter.class);
StatelessPartitioner&lt;JsonFormatter&gt; partitioner1 = new StatelessPartitioner&lt;JsonFormatter&gt;(2);
dag.setAttribute(jsonFormatter, Context.OperatorContext.PARTITIONER, partitioner1 );
</code></pre>
<ol>
<li>Specifying the partitioner in properties file.</li>
</ol>
<pre><code class="xml"> &lt;property&gt;
&lt;name&gt;dt.operator.{OperatorName}.attr.PARTITIONER&lt;/name&gt;
&lt;value&gt;com.datatorrent.common.partitioner.StatelessPartitioner:2&lt;/value&gt;
&lt;/property&gt;
</code></pre>
<p>where {OperatorName} is the name of the JsonFormatter operator.
Above lines will partition JsonFormatter statically 2 times. Above value can be changed accordingly to change the number of static partitions.</p>
<h3 id="dynamic-paritioning">Dynamic Paritioning</h3>
<p>JsonFormatter can be dynamically partitioned using an out-of-the-box partitioner:</p>
<h4 id="throughput-based">Throughput based</h4>
<p>Following code can be added to populateDAG method of application to dynamically partition JsonFormatter:</p>
<pre><code class="java">JsonFormatter jsonFormatter = dag.addOperator(&quot;jsonFormatter&quot;, JsonFormatter.class);
StatelessThroughputBasedPartitioner&lt;JsonFormatter&gt; partitioner = new StatelessThroughputBasedPartitioner&lt;&gt;();
partitioner.setCooldownMillis(conf.getLong(COOL_DOWN_MILLIS, 10000));
partitioner.setMaximumEvents(conf.getLong(MAX_THROUGHPUT, 30000));
partitioner.setMinimumEvents(conf.getLong(MIN_THROUGHPUT, 10000));
dag.setAttribute(JsonFormatter, OperatorContext.STATS_LISTENERS, Arrays.asList(new StatsListener[]{partitioner}));
dag.setAttribute(JsonFormatter, OperatorContext.PARTITIONER, partitioner);
</code></pre>
<p>Above code will dynamically partition JsonFormatter when the throughput changes.
If the overall throughput of JsonFormatter goes beyond 30000 or less than 10000, the platform will repartition JsonFormatter
to balance throughput of a single partition to be between 10000 and 30000.
CooldownMillis of 10000 will be used as the threshold time for which the throughput change is observed.</p>
<h2 id="example">Example</h2>
<p>Example for Json Formatter can be found at: <a href="https://github.com/DataTorrent/examples/tree/master/tutorials/parser">https://github.com/DataTorrent/examples/tree/master/tutorials/parser</a></p>
<h2 id="advance-features">Advance Features</h2>
<p>JsonFormatter is based on <a href="https://github.com/FasterXML/jackson-databind">jackson-databind</a> and so users can make use of <a href="https://github.com/FasterXML/jackson-annotations">annotations</a> in POJO class. Here are few annotations that are relavant while using JsonFormatter
1. <strong>@JsonProperty</strong> : Sometimes POJOs contain properties that has different name from incoming POJOs.You can specify names as:</p>
<pre><code class="java">public class Ad{
@JsonProperty(&quot;desc&quot;)
public String description;
public List&lt;String&gt; sizes;
}
</code></pre>
<ol>
<li><strong>@JsonIgnore</strong> : Sometimes POJOs contain properties that you do not want to write out, so you can do:</li>
</ol>
<pre><code class="java">public class Value {
public int value;
@JsonIgnore
public int internalValue;
}
</code></pre>
<ol>
<li><strong>@JsonFormat</strong> : Sometimes Date fields need to be printed in custom format, so you can do:</li>
</ol>
<pre><code class="java">public class Ad{
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = &quot;EEE, d MMM yyyy HH:mm:ss&quot;)
public Date startDate;
}
</code></pre>
</div>
</div>
<footer>
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
<a href="../jsonParser/" class="btn btn-neutral float-right" title="JSON Parser">Next <span class="icon icon-circle-arrow-right"></span></a>
<a href="../jmsInputOperator/" class="btn btn-neutral" title="JMS Input"><span class="icon icon-circle-arrow-left"></span> Previous</a>
</div>
<hr/>
<div role="contentinfo">
<!-- Copyright etc -->
</div>
Built with <a href="http://www.mkdocs.org">MkDocs</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<div class="rst-versions" role="note" style="cursor: pointer">
<span class="rst-current-version" data-toggle="rst-current-version">
<span><a href="../jmsInputOperator/" style="color: #fcfcfc;">&laquo; Previous</a></span>
<span style="margin-left: 15px"><a href="../jsonParser/" style="color: #fcfcfc">Next &raquo;</a></span>
</span>
</div>
</body>
</html>