blob: 898ff4f6d39990fbd113498a92ba9a0587d24c4b [file] [log] [blame]
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="keywords" content=" ">
<title>Getting started with Apache Edgent | Apache Edgent Documentation</title>
<link rel="stylesheet" type="text/css" href="../css/syntax.css">
<link rel="stylesheet" type="text/css" href="../css/font-awesome.min.css">
<!--<link rel="stylesheet" type="text/css" href="../css/bootstrap.min.css">-->
<link rel="stylesheet" type="text/css" href="../css/modern-business.css">
<link rel="stylesheet" type="text/css" href="../css/lavish-bootstrap.css">
<link rel="stylesheet" type="text/css" href="../css/customstyles.css">
<link rel="stylesheet" type="text/css" href="../css/theme-blue.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script src="../js/jquery.navgoco.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/anchor-js/2.0.0/anchor.min.js"></script>
<script src="../js/toc.js"></script>
<script src="../js/customscripts.js"></script>
<link rel="shortcut icon" href="../common_images/favicon.ico" type="image/x-icon">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<script>
$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
</script>
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container topnavlinks">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="fa fa-home fa-lg navbar-brand" href="../docs/home.html">&nbsp;<span class="projectTitle"> Apache Edgent Documentation</span></a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<!-- entries without drop-downs appear here -->
<!-- conditional logic to control which topnav appears for the audience defined in the configuration file.-->
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">GitHub Repos<b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="https://github.com/apache/incubator-edgent" target="_blank">Source code</a></li>
<li><a href="https://github.com/apache/incubator-edgent-samples" target="_blank">Edgent Samples</a></li>
<li><a href="https://github.com/apache/incubator-edgent-website" target="_blank">Website/Documentation</a></li>
</ul>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Javadoc<b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="..\javadoc\latest">latest</a></li>
<li><a href="..\javadoc\r1.2.0">1.2.0</a></li>
<li><a href="..\javadoc\r1.1.0">1.1.0</a></li>
<li><a href="..\javadoc\r1.0.0">1.0.0</a></li>
<li><a href="..\javadoc\r0.4.0">0.4.0</a></li>
</ul>
</li>
<!-- entries with drop-downs appear here -->
<!-- conditional logic to control which topnav appears for the audience defined in the configuration file.-->
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Edgent Resources<b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="downloads">Download</a></li>
<li><a href="faq">FAQ</a></li>
<li class="dropdownActive"><a href="/">edgent.apache.org</a></li>
</ul>
</li>
<!-- special insertion -->
<!-- Send feedback function -->
<script>
function SendLinkByMail(href) {
var subject= "Apache Edgent Documentation feedback";
var body = "I have some feedback about the Getting started with Apache Edgent page: ";
body += window.location.href;
body += "";
var uri = "mailto:?subject=";
uri += encodeURIComponent(subject);
uri += "&body=";
uri += encodeURIComponent(body);
window.location.href = uri;
}
</script>
<li><a href="mailto:dev@edgent.incubator.apache.org" target="_blank"><i class="fa fa-envelope-o"></i> Feedback</a></li>
<!--uncomment this block if you want simple search instead of algolia-->
<li>
<!--start search-->
<div id="search-demo-container">
<input type="text" id="search-input" placeholder="search...">
<ul id="results-container"></ul>
</div>
<script src="../js/jekyll-search.js" type="text/javascript"></script>
<script type="text/javascript">
SimpleJekyllSearch.init({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('results-container'),
dataSource: '../search.json',
searchResultTemplate: '<li><a href="{url}" title="Getting started with Apache Edgent">{title}</a></li>',
noResultsText: 'No results found.',
limit: 10,
fuzzy: true,
})
</script>
<!--end search-->
</li>
</div>
<!-- /.container -->
</nav>
<!-- Page Content -->
<div class="container">
<div class="col-lg-12">&nbsp;</div>
<!-- Content Row -->
<div class="row">
<!-- Sidebar Column -->
<div class="col-md-3">
<script>
$(document).ready(function() {
// Initialize navgoco with default options
$("#mysidebar").navgoco({
caretHtml: '',
accordion: true,
openClass: 'active', // open
save: true,
cookie: {
name: 'navgoco',
expires: false,
path: '/'
},
slide: {
duration: 400,
easing: 'swing'
}
});
$("#collapseAll").click(function(e) {
e.preventDefault();
$("#mysidebar").navgoco('toggle', false);
});
$("#expandAll").click(function(e) {
e.preventDefault();
$("#mysidebar").navgoco('toggle', true);
});
});
</script>
<ul id="mysidebar" class="nav">
<span class="siteTagline">Edgent</span>
<span class="versionTagline">Version 1.2.0-incubating</span>
<li><a href="#">Overview</a>
<ul>
<li><a href="../docs/edgent_index.html">Introduction</a></li>
<li><a href="../docs/home.html">Edgent Overview</a></li>
<li><a href="../docs/power-of-edgent.html">The Power of Edgent</a></li>
<li><a href="../docs/faq.html">FAQ</a></li>
</ul>
<li><a href="#">Get Started</a>
<ul>
<li><a href="../docs/downloads.html">Downloads</a></li>
<li class="active"><a href="../docs/edgent-getting-started.html">Getting Started Guide</a></li>
<li><a href="../docs/edgent-getting-started-samples.html">Quickstart with Edgent Samples</a></li>
<li><a href="../docs/application-development.html">Understanding App Development</a></li>
<li><a href="../docs/quickstart.html">Quickstart IBM Watson IoT Platform</a></li>
<li><a href="../docs/streaming-concepts.html">Streaming concepts</a></li>
<li><a href="../docs/common-edgent-operations.html">Common operations</a></li>
</ul>
<li><a href="#">Edgent Cookbook</a>
<ul>
<li><a href="../recipes/recipe_hello_edgent.html">Hello Edgent!</a></li>
<li><a href="../recipes/recipe_source_function.html">Writing a source function</a></li>
<li><a href="../recipes/recipe_value_out_of_range.html">Detecting a sensor value out of expected range</a></li>
<li><a href="../recipes/recipe_different_processing_against_stream.html">Applying different processing against a single stream</a></li>
<li><a href="../recipes/recipe_combining_streams_processing_results.html">Splitting a stream to apply different processing and combining the results into a single stream</a></li>
<li><a href="../recipes/recipe_external_filter_range.html">Using an external configuration file for filter ranges</a></li>
<li><a href="../recipes/recipe_adaptable_filter_range.html">Changing a filter's range</a></li>
<li><a href="../recipes/recipe_adaptable_polling_source.html">Changing a polled source stream's period</a></li>
<li><a href="../recipes/recipe_adaptable_deadtime_filter.html">Using an adaptable deadtime filter</a></li>
<li><a href="../recipes/recipe_dynamic_analytic_control.html">Dynamically enabling analytic flows</a></li>
<li><a href="../recipes/recipe_parallel_analytics.html">How can I run analytics on several tuples in parallel?</a></li>
<li><a href="../recipes/recipe_concurrent_analytics.html">How can I run several analytics on a tuple concurrently?</a></li>
<li><a href="../recipes/recipe_writing_a_connector.html">How do I write a connector?</a></li>
</ul>
<li><a href="#">Using the Console</a>
<ul>
<li><a href="../docs/console.html">Using the console</a></li>
</ul>
<li><a href="#">Get Involved</a>
<ul>
<li><a href="../docs/community.html">How to participate</a></li>
<li><a href="../docs/committers.html">Committers</a></li>
</ul>
<!-- if you aren't using the accordion, uncomment this block:
<p class="external">
<a href="#" id="collapseAll">Collapse All</a> | <a href="#" id="expandAll">Expand All</a>
</p>
-->
<br/>
</li>
</ul>
<div class="row">
<div class="col-md-12">
<!-- this handles the automatic toc. use ## for subheads to auto-generate the on-page minitoc. if you use html tags, you must supply an ID for the heading element in order for it to appear in the minitoc. -->
<script>
$( document ).ready(function() {
// Handler for .ready() called.
$('#toc').toc({ minimumHeaders: 0, listType: 'ul', showSpeed: 0, headers: 'h2,h3,h4' });
/* this offset helps account for the space taken up by the floating toolbar. */
$('#toc').on('click', 'a', function() {
var target = $(this.getAttribute('href'))
, scroll_target = target.offset().top
$(window).scrollTop(scroll_target - 10);
return false
})
});
</script>
<div id="toc"></div>
</div>
</div>
</div>
<!-- this highlights the active parent class in the navgoco sidebar. this is critical so that the parent expands when you're viewing a page. This must appear below the sidebar code above. Otherwise, if placed inside customscripts.js, the script runs before the sidebar code runs and the class never gets inserted.-->
<script>$("li.active").parents('li').toggleClass("active");</script>
<!-- Content Column -->
<div class="col-md-9">
<div class="post-header">
<h1 class="post-title-main">Getting started with Apache Edgent</h1>
</div>
<div class="post-content">
<!-- this handles the automatic toc. use ## for subheads to auto-generate the on-page minitoc. if you use html tags, you must supply an ID for the heading element in order for it to appear in the minitoc. -->
<script>
$( document ).ready(function() {
// Handler for .ready() called.
$('#toc').toc({ minimumHeaders: 0, listType: 'ul', showSpeed: 0, headers: 'h2,h3,h4' });
/* this offset helps account for the space taken up by the floating toolbar. */
$('#toc').on('click', 'a', function() {
var target = $(this.getAttribute('href'))
, scroll_target = target.offset().top
$(window).scrollTop(scroll_target - 10);
return false
})
});
</script>
<div id="toc"></div>
<a target="_blank" href="https://github.com/apache/incubator-edgent-website/blob/master/site/docs/edgent-getting-started.md" class="btn btn-default githubEditButton" role="button"><i class="fa fa-github fa-lg"></i> Edit me</a>
<h2 id="what-is-apache-edgent">What is Apache Edgent?</h2>
<p>Edgent is an open source programming model and runtime for edge devices that enables you to analyze streaming data on your edge devices. When you analyze on the edge, you can:</p>
<ul>
<li>Reduce the amount of data that you transmit to your analytics server</li>
<li>Reduce the amount of data that you store</li>
</ul>
<p>Edgent accellerates your development of applications to push data analytics and machine learning to <em>edge devices</em>. (Edge devices include things like routers, gateways, machines, equipment, sensors, appliances, or vehicles that are connected to a network.) Edgent applications process data locally&mdash;such as, in a car, on an Android phone, or on a Raspberry Pi&mdash;before it sends data over a network.</p>
<p>For example, if your device takes temperature readings from a sensor 1,000 times per second, it is more efficient to process the data locally and send only interesting or unexpected results over the network.</p>
<p>See <a href="power-of-edgent">The Power of Edgent</a> to help you quickly start to get a sense of Edgent&#39;s capabilities.</p>
<p>Releases of Edgent prior to 1.2.0 distributed Edgent and the samples differently than today. See <a href="old-edgent-getting-started">Old Getting Started</a> if you are trying to use an older version.</p>
<p>There&#39;s a lot of information available to get started with Edgent and no &quot;best order&quot; for navigating it. See the navigation sidebar on the left hand side of this page. In particular it is recommended that you review and visit the various items under <em>Get Started</em>.</p>
<p>If you want to get a developent environment setup quickly see the <a href="edgent-getting-started-samples">Quickstart with Edgent Samples</a> item. </p>
<p>The <em>Edgent Cookbook</em> topic includes many well documented recipies that are good for learning and jump-starting the development of your application.</p>
<p>The rest of this page is a detailed introduction to Edgent using a simple simulated Temperature Sensor application.</p>
<h2 id="apache-edgent-and-streaming-analytics">Apache Edgent and streaming analytics</h2>
<p>The fundamental building block of an Edgent application is a <strong>stream</strong>: a continuous sequence of tuples (messages, events, sensor readings, and so on).</p>
<p>The Edgent API provides the ability to process or analyze each tuple as it appears on a stream, resulting in a derived stream.</p>
<p>Source streams are streams that originate data for analysis, such as readings from a device&#39;s temperature sensor.</p>
<p>Streams are terminated using sink functions that can perform local device control or send information to external services such as centralized analytic systems through a message hub.</p>
<p>Edgent&#39;s primary API is functional where streams are sourced, transformed, analyzed or sinked though functions, typically represented as Java8 lambda expressions, such as <code>reading -&gt; reading &lt; 50 || reading &gt; 80</code> to filter temperature readings in Fahrenheit.</p>
<p>A <strong>topology</strong> is a graph of streams and their processing transformations. A <strong>provider</strong> is a factory for creating and executing topologies.</p>
<p>Basic Edgent Applications follow a common structure:</p>
<ol>
<li>Get a provider</li>
<li>Create the topology and compose its processing graph</li>
<li>Submit the topology for execution</li>
</ol>
<p>More sophisticated applications may consist of multiple topologies that may be dynamically created and started and stopped using commands from external applications.</p>
<h2 id="temperature-sensor-application">Temperature Sensor Application</h2>
<p>If you&#39;re new to Edgent or to writing streaming applications, the best way to get started is to write a simple program.</p>
<p>First we&#39;ll go over the details of the application, then we&#39;ll run it.</p>
<p>Let&#39;s create a simple Temperature Sensor Application. The application takes temperature readings from a sensor 1,000 times per second. Instead of reporting each reading, it is more efficient to process the data locally and send only interesting or unexpected results over the network.</p>
<p>To simulate this, let&#39;s define a (simulated) TempSensor class:</p>
<div class="highlight"><pre><code class="language-java" data-lang="java"><span class="kn">import</span> <span class="nn">java.util.Random</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.apache.edgent.function.Supplier</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">TempSensor</span> <span class="kd">implements</span> <span class="n">Supplier</span><span class="o">&lt;</span><span class="n">Double</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="kt">double</span> <span class="n">currentTemp</span> <span class="o">=</span> <span class="mf">65.0</span><span class="o">;</span>
<span class="n">Random</span> <span class="n">rand</span><span class="o">;</span>
<span class="n">TempSensor</span><span class="o">(){</span>
<span class="n">rand</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Random</span><span class="o">();</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">Double</span> <span class="n">get</span><span class="o">()</span> <span class="o">{</span>
<span class="c1">// Change the current temperature some random amount</span>
<span class="kt">double</span> <span class="n">newTemp</span> <span class="o">=</span> <span class="n">rand</span><span class="o">.</span><span class="na">nextGaussian</span><span class="o">()</span> <span class="o">+</span> <span class="n">currentTemp</span><span class="o">;</span>
<span class="n">currentTemp</span> <span class="o">=</span> <span class="n">newTemp</span><span class="o">;</span>
<span class="k">return</span> <span class="n">currentTemp</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div>
<p>Every time <code>TempSensor.get()</code> is called, it returns a new temperature reading.</p>
<p>Our application composes a topology that creates a continuous stream of temperature readings and processes this stream by filtering the data and printing the results. Let&#39;s define a TempSensorApplication class for the application:</p>
<div class="highlight"><pre><code class="language-java" data-lang="java"><span class="kn">import</span> <span class="nn">java.util.concurrent.TimeUnit</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.apache.edgent.providers.direct.DirectProvider</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.apache.edgent.topology.TStream</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.apache.edgent.topology.Topology</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">TempSensorApplication</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="n">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">Exception</span> <span class="o">{</span>
<span class="n">TempSensor</span> <span class="n">sensor</span> <span class="o">=</span> <span class="k">new</span> <span class="n">TempSensor</span><span class="o">();</span>
<span class="n">DirectProvider</span> <span class="n">dp</span> <span class="o">=</span> <span class="k">new</span> <span class="n">DirectProvider</span><span class="o">();</span>
<span class="n">Topology</span> <span class="n">topology</span> <span class="o">=</span> <span class="n">dp</span><span class="o">.</span><span class="na">newTopology</span><span class="o">();</span>
<span class="n">TStream</span><span class="o">&lt;</span><span class="n">Double</span><span class="o">&gt;</span> <span class="n">tempReadings</span> <span class="o">=</span> <span class="n">topology</span><span class="o">.</span><span class="na">poll</span><span class="o">(</span><span class="n">sensor</span><span class="o">,</span> <span class="mi">1</span><span class="o">,</span> <span class="n">TimeUnit</span><span class="o">.</span><span class="na">MILLISECONDS</span><span class="o">);</span>
<span class="n">TStream</span><span class="o">&lt;</span><span class="n">Double</span><span class="o">&gt;</span> <span class="n">filteredReadings</span> <span class="o">=</span> <span class="n">tempReadings</span><span class="o">.</span><span class="na">filter</span><span class="o">(</span><span class="n">reading</span> <span class="o">-&gt;</span> <span class="n">reading</span> <span class="o">&lt;</span> <span class="mi">50</span> <span class="o">||</span> <span class="n">reading</span> <span class="o">&gt;</span> <span class="mi">80</span><span class="o">);</span>
<span class="n">filteredReadings</span><span class="o">.</span><span class="na">print</span><span class="o">();</span>
<span class="n">dp</span><span class="o">.</span><span class="na">submit</span><span class="o">(</span><span class="n">topology</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div>
<p>Let&#39;s review each line.</p>
<h3 id="specifying-a-provider">Specifying a provider</h3>
<p>Your first step when you write an Edgent application is to create a <em>Provider</em>. In this case we&#39;re using a <a href="/javadoc/latest/index.html?org/apache/edgent/providers/direct/DirectProvider.html">DirectProvider</a>:</p>
<div class="highlight"><pre><code class="language-java" data-lang="java"><span class="n">DirectProvider</span> <span class="n">dp</span> <span class="o">=</span> <span class="k">new</span> <span class="n">DirectProvider</span><span class="o">();</span>
</code></pre></div>
<p>A <code>Provider</code> is an object that contains information on how and where your Edgent application will run. A <code>DirectProvider</code> is a type of Provider that runs your application directly within the current virtual machine when its <a href="/javadoc/latest/org/apache/edgent/providers/direct/DirectProvider.html#submit-org.apache.edgent.topology.Topology-">submit()</a> method is called.</p>
<p>The <a href="/javadoc/latest/index.html?org/apache/edgent/providers/iot/IotProvider.html">IotProvider</a> is an alternative that offers very useful and powerful capabilities.</p>
<h3 id="creating-a-topology">Creating a topology</h3>
<p>The Provider is used to create a <a href="/javadoc/latest/index.html?org/apache/edgent/topology/Topology.html">Topology</a> instance:</p>
<div class="highlight"><pre><code class="language-java" data-lang="java"><span class="n">Topology</span> <span class="n">topology</span> <span class="o">=</span> <span class="n">dp</span><span class="o">.</span><span class="na">newTopology</span><span class="o">();</span>
</code></pre></div>
<p>In Edgent, <code>Topology</code> is a container that describes the structure of your processing graph:</p>
<ul>
<li>Where the streams in the application come from</li>
<li>How the data in the stream is modified</li>
</ul>
<p>Our application then composes the topology&#39;s progessing graph.</p>
<h3 id="creating-a-source-tstream">Creating a source <code>TStream</code></h3>
<p>In the <code>TempSensorApplication</code> class above, we have exactly one data source: the <code>TempSensor</code> object. We define the source stream by calling <a href="/javadoc/latest/org/apache/edgent/topology/Topology.html#poll-org.apache.edgent.function.Supplier-long-java.util.concurrent.TimeUnit-">topology.poll()</a>, which takes both a <a href="/javadoc/latest/index.html?org/apache/edgent/function/Supplier.html">Supplier</a> function and a time parameter to indicate how frequently readings should be taken. In our case, we read from the sensor every millisecond:</p>
<div class="highlight"><pre><code class="language-java" data-lang="java"><span class="n">TStream</span><span class="o">&lt;</span><span class="n">Double</span><span class="o">&gt;</span> <span class="n">tempReadings</span> <span class="o">=</span> <span class="n">topology</span><span class="o">.</span><span class="na">poll</span><span class="o">(</span><span class="n">sensor</span><span class="o">,</span> <span class="mi">1</span><span class="o">,</span> <span class="n">TimeUnit</span><span class="o">.</span><span class="na">MILLISECONDS</span><span class="o">);</span>
</code></pre></div>
<p>Calling <code>topology.poll()</code> to define a source stream creates a <code>TStream&lt;Double&gt;</code> instance (because <code>TempSensor.get()</code> returns a <code>Double</code>), which represents the series of readings taken from the temperature sensor.</p>
<p>A streaming application can run indefinitely, so the <a href="/javadoc/latest/index.html?org/apache/edgent/topology/TStream.html">TStream</a> might see an arbitrarily large number of readings pass through it. Because a <code>TStream</code> represents the flow of your data, it supports a number of operations which allow you to modify your data.</p>
<h3 id="filtering-a-tstream">Filtering a <code>TStream</code></h3>
<p>In our example, we want to filter the stream of temperature readings, and remove any &quot;uninteresting&quot; or expected readings&mdash;specifically readings which are above 50 degrees and below 80 degrees. To do this, we call the <code>TStream</code>&#39;s <a href="/javadoc/latest/org/apache/edgent/topology/TStream.html#filter-org.apache.edgent.function.Predicate-">filter</a> method and pass in a function that returns <em>true</em> if the data is interesting and <em>false</em> if the data is uninteresting:</p>
<div class="highlight"><pre><code class="language-java" data-lang="java"><span class="n">TStream</span><span class="o">&lt;</span><span class="n">Double</span><span class="o">&gt;</span> <span class="n">filteredReadings</span> <span class="o">=</span> <span class="n">tempReadings</span><span class="o">.</span><span class="na">filter</span><span class="o">(</span><span class="n">reading</span> <span class="o">-&gt;</span> <span class="n">reading</span> <span class="o">&lt;</span> <span class="mi">50</span> <span class="o">||</span> <span class="n">reading</span> <span class="o">&gt;</span> <span class="mi">80</span><span class="o">);</span>
</code></pre></div>
<p>As you can see, the function that is passed to <code>filter</code> operates on each tuple individually. Unlike data streaming frameworks like <a href="https://spark.apache.org/">Apache Spark</a>, which operate on a collection of data in batch mode, Edgent achieves low latency processing by manipulating each piece of data as soon as it becomes available. Filtering a <code>TStream</code> produces another <code>TStream</code> that contains only the filtered tuples; in this case, the <code>filteredReadings</code> stream.</p>
<h3 id="printing-to-output">Printing to output</h3>
<p>When our application detects interesting data (data outside of the expected parameters), we want to print results. You can do this by calling the <a href="/javadoc/latest/org/apache/edgent/topology/TStream.html#print--">TStream.print()</a> method, which prints using <code>.toString()</code> on each tuple that passes through the stream:</p>
<div class="highlight"><pre><code class="language-java" data-lang="java"><span class="n">filteredReadings</span><span class="o">.</span><span class="na">print</span><span class="o">();</span>
</code></pre></div>
<p>Unlike <code>TStream.filter()</code>, <code>TStream.print()</code> does not produce another <code>TStream</code>. This is because <code>TStream.print()</code> is a <strong>sink</strong>, which represents the terminus of a stream.</p>
<p>A real application typically publishes results to an MQTT server, IoT Hub, Kafka cluster, file, JDBC connection, or other external system. Edgent comes easy to use connectors for these. See the <em>connectors</em> samples, <a href="/javadoc/latest">Edgent Javadoc</a>, and <em>Edgent Cookbook</em> for more information.</p>
<p>You can define your own sink by invoking <a href="/javadoc/latest/org/apache/edgent/topology/TStream.html#sink-org.apache.edgent.function.Consumer-">TStream.sink()</a> and passing in your own function.</p>
<h3 id="submitting-your-topology">Submitting your topology</h3>
<p>Now that your topology / processing graph has been completely declared, the final step is to run it.</p>
<p><code>DirectProvider</code> contains a <code>submit()</code> method, which runs a topology directly within the current virtual machine:</p>
<div class="highlight"><pre><code class="language-java" data-lang="java"><span class="n">dp</span><span class="o">.</span><span class="na">submit</span><span class="o">(</span><span class="n">topology</span><span class="o">);</span>
</code></pre></div>
<p>After you run your program, you should see output containing only &quot;interesting&quot; data coming from your sensor:</p>
<div class="highlight"><pre><code class="language-" data-lang="">49.904032311772596
47.97837504039084
46.59272336309031
46.681544551652934
47.400819234155236
...
</code></pre></div>
<p>As you can see, all temperatures are outside the 50-80 degree range. In terms of a real-world application, this would prevent a device from sending superfluous data over a network, thereby reducing communication costs.</p>
<h3 id="building-and-running">Building and Running</h3>
<p>Its easiest to use the Edgent Samples Source release to get started.</p>
<p>If you just want to see this application in action, it&#39;s one of the provided samples!</p>
<p>Go to <a href="edgent-getting-started-samples">Getting Started with Samples</a> to get and build the samples.</p>
<p>Then you can run this application from the command line:</p>
<div class="highlight"><pre><code class="language-sh" data-lang="sh"><span class="nb">cd</span> &lt;the-unpacked-samples-root-folder&gt;
<span class="nb">cd </span>topology; ./run-sample.sh TempSensorApplication
46.59272336309031
46.681544551652934
...
^C to terminate it
</code></pre></div>
<p>If you setup an Eclipse workspace with the samples, you can run the application from Eclipse:</p>
<ol>
<li>From the Eclipse <em>Navigate</em> menu, select <em>Open Type</em>
<ul>
<li>enter type type name <code>TempSensorApplication</code> and click <em>OK</em></li>
</ul></li>
<li>right click on the <code>TempSensorApplication</code> class name and from the context menu
<ul>
<li>click on <em>Run As</em>, then <em>Java application</em>.<br>
<code>TempSensorApplication</code> runs and prints to the Console view.
Click on the <code>terminate</code> control in the Console view to stop the application.</li>
</ul></li>
</ol>
<h3 id="creating-your-own-project">Creating your own project</h3>
<p>In this flow we&#39;ll take you though creating a new project for this application.
Its easiest to use the <code>template</code> project in the Edgent Samples to get started.</p>
<p>Go to <a href="edgent-getting-started-samples">Getting Started with Samples</a> and follow the steps to</p>
<ul>
<li>do the general samples setup</li>
<li>clone the <code>template</code> project to use for this application</li>
</ul>
<p>Then create the <code>TempSensor.java</code> and <code>TempSensorApplication.java</code> files in the project, copying in the above code.</p>
<p>To build and run from the command line, see the new project&#39;s README.md (copied in from the template).
In the project&#39;s folder (adjust the package name below if appropriate)</p>
<div class="highlight"><pre><code class="language-sh" data-lang="sh">./mvnw clean package
./app-run.sh --main com.mycompany.app.TempSensorApplication
46.59272336309031
46.681544551652934
...
^C to terminate it
</code></pre></div>
<p>If you setup the cloned template in an Eclipse workspace:</p>
<ol>
<li>From the Eclipse <em>Navigate</em> menu, select <em>Open Type</em>
<ul>
<li>enter type type name <code>TempSensorApplication</code> and click <em>OK</em></li>
</ul></li>
<li>right click on the <code>TempSensorApplication</code> class name and from the context menu
<ul>
<li>click on <em>Run As</em>, then <em>Java application</em>.<br>
<code>TempSensorApplication</code> runs and prints to the Console view.
Click on the <code>terminate</code> control in the Console view to stop the application.</li>
</ul></li>
</ol>
<h2 id="next-steps">Next Steps</h2>
<p>This introduction demonstrates a small piece of Edgent&#39;s functionality. Edgent supports more complicated topologies, such as topologies that require merging and splitting data streams, or perform operations which aggregate the last <em>N</em> seconds of data (for example, calculating a moving average). Typically your application will want to publish to an IoT hub and be controlled by applications in a data center.</p>
<p>There are many more useful resources under the <em>Get Started</em> and <em>Edgent Cookbook</em> topics in the navigation sidebar on the left hand side of this page.</p>
<div class="tags">
</div>
<!--
<div id="disqus_thread"></div>
<script type="text/javascript">
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = 'idrbwjekyll'; // required: replace example with your forum shortname
/* * * DON'T EDIT BELOW THIS LINE * * */
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
-->
</div>
<footer>
<div class="row">
<div class="col-lg-12 footer">
Site last
generated: Dec 18, 2017 <br/>
</div>
</div>
<br/>
<div class="row">
<div class="col-md-12">
<p class="small">Apache Edgent is an effort undergoing Incubation at The Apache Software
Foundation (ASF), sponsored by the Incubator. Incubation is required of all newly accepted projects
until a further review indicates that the infrastructure, communications, and decision making process
have stabilized in a manner consistent with other successful ASF projects. While incubation status is
not necessarily a reflection of the completeness or stability of the code, it does indicate that the
project has yet to be fully endorsed by the ASF.</p>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p class="small">Copyright © 2016 The Apache Software Foundation. Licensed under the Apache
License, Version 2.0.
Apache, the Apache Feather logo, and the Apache Incubator project logo are trademarks of The Apache
Software Foundation. All other marks mentioned may be trademarks or registered trademarks of their
respective owners.</p>
</div>
</div>
<div class="container">
<div class="row">
<div>
<img class="img-responsive center-block" src="../img/edgent_incubation.png" style="display: block; margin: auto;"alt="">
</div>
</div>
</footer>
</div><!-- /.row -->
</div> <!-- /.container -->
</body>
</html>