mirror of
https://github.com/apache/zeppelin
synced 2026-05-24 09:38:26 +00:00
merge with master
This commit is contained in:
commit
cb993914c4
74 changed files with 2015 additions and 654 deletions
|
|
@ -22,17 +22,17 @@ before_install:
|
|||
- "sh -e /etc/init.d/xvfb start"
|
||||
|
||||
install:
|
||||
- mvn package -DskipTests -Phadoop-2.3 -Ppyspark -B
|
||||
- mvn package -DskipTests -Pspark-1.5 -Phadoop-2.3 -Ppyspark -B
|
||||
|
||||
before_script:
|
||||
-
|
||||
|
||||
script:
|
||||
# spark 1.5
|
||||
- mvn package -Pbuild-distr -Phadoop-2.3 -Ppyspark -B
|
||||
- mvn package -Pbuild-distr -Pspark-1.5 -Phadoop-2.3 -Ppyspark -B
|
||||
- ./testing/startSparkCluster.sh 1.5.2 2.3
|
||||
- echo "export SPARK_HOME=`pwd`/spark-1.5.2-bin-hadoop2.3" > conf/zeppelin-env.sh
|
||||
- mvn verify -Pusing-packaged-distr -Phadoop-2.3 -Ppyspark -B
|
||||
- mvn verify -Pusing-packaged-distr -Pspark-1.5 -Phadoop-2.3 -Ppyspark -B
|
||||
- ./testing/stopSparkCluster.sh 1.5.2 2.3
|
||||
# spark 1.4
|
||||
- rm -rf `pwd`/interpreter/spark
|
||||
|
|
|
|||
172
README.md
172
README.md
|
|
@ -49,133 +49,109 @@ _Notes:_
|
|||
If you want to build Zeppelin from the source, please first clone this repository, then:
|
||||
|
||||
```
|
||||
mvn clean package -DskipTests
|
||||
mvn clean package -DskipTests [Options]
|
||||
```
|
||||
|
||||
To build with a specific Spark version, Hadoop version or specific features, define one or more of the `spark`, `pyspark`, `hadoop` and `yarn` profiles, such as:
|
||||
Each Interpreter requires different Options.
|
||||
|
||||
|
||||
#### Spark Interpreter
|
||||
|
||||
To build with a specific Spark version, Hadoop version or specific features, define one or more of the following profiles and options:
|
||||
|
||||
##### -Pspark-[version]
|
||||
|
||||
Set spark major version
|
||||
|
||||
Available profiles are
|
||||
|
||||
```
|
||||
-Pspark-1.5 [Version to run in local spark mode]
|
||||
-Ppyspark [optional: enable PYTHON support in spark via the %pyspark interpreter]
|
||||
-Pyarn [optional: enable YARN support]
|
||||
-Dhadoop.version=2.2.0 [hadoop distribution]
|
||||
-Phadoop-2.2 [hadoop version]
|
||||
-Pspark-1.5
|
||||
-Pspark-1.4
|
||||
-Pspark-1.3
|
||||
-Pspark-1.2
|
||||
-Pspark-1.1
|
||||
-Pcassandra-spark-1.5
|
||||
-Pcassandra-spark-1.4
|
||||
-Pcassandra-spark-1.3
|
||||
-Pcassandra-spark-1.2
|
||||
-Pcassandra-spark-1.1
|
||||
```
|
||||
|
||||
Currently, final/full distributions run with:
|
||||
minor version can be adjusted by `-Dspark.version=x.x.x`
|
||||
|
||||
|
||||
##### -Phadoop-[version]
|
||||
|
||||
set hadoop major version
|
||||
|
||||
Available profiles are
|
||||
|
||||
```
|
||||
mvn clean package -Pspark-1.5 -Phadoop-2.4 -Pyarn -Ppyspark
|
||||
-Phadoop-0.23
|
||||
-Phadoop-1
|
||||
-Phadoop-2.2
|
||||
-Phadoop-2.3
|
||||
-Phadoop-2.4
|
||||
-Phadoop-2.6
|
||||
```
|
||||
|
||||
Spark 1.5.x
|
||||
minor version can be adjusted by `-Dhadoop.version=x.x.x`
|
||||
|
||||
```
|
||||
mvn clean package -Pspark-1.5 -Dhadoop.version=2.2.0 -Phadoop-2.2 -DskipTests
|
||||
```
|
||||
Spark 1.4.x
|
||||
##### -Pyarn (optional)
|
||||
|
||||
```
|
||||
mvn clean package -Pspark-1.4 -Dhadoop.version=2.2.0 -Phadoop-2.2 -DskipTests
|
||||
```
|
||||
Spark 1.3.x
|
||||
enable YARN support for local mode
|
||||
|
||||
```
|
||||
mvn clean package -Pspark-1.3 -Dhadoop.version=2.2.0 -Phadoop-2.2 -DskipTests
|
||||
```
|
||||
Spark 1.2.x
|
||||
|
||||
```
|
||||
mvn clean package -Pspark-1.2 -Dhadoop.version=2.2.0 -Phadoop-2.2 -DskipTests
|
||||
```
|
||||
Spark 1.1.x
|
||||
##### -Ppyspark (optional)
|
||||
|
||||
```
|
||||
mvn clean package -Pspark-1.1 -Dhadoop.version=2.2.0 -Phadoop-2.2 -DskipTests
|
||||
```
|
||||
CDH 5.X
|
||||
enable PySpark support for local mode
|
||||
|
||||
|
||||
##### -Pvendor-repo (optional)
|
||||
|
||||
enable 3rd party vendor repository (cloudera)
|
||||
|
||||
|
||||
##### -Pmapr[version] (optional)
|
||||
|
||||
```
|
||||
mvn clean package -Pspark-1.2 -Dhadoop.version=2.5.0-cdh5.3.0 -Phadoop-2.4 -DskipTests
|
||||
```
|
||||
For the MapR Hadoop Distribution, these profiles will handle the Hadoop version. As MapR allows different versions
|
||||
of Spark to be installed, you should specify which version of Spark is installed on the cluster by adding a Spark profile (-Pspark-1.2, -Pspark-1.3, etc.) as needed. For Hive, check the hive/pom.xml and adjust the version installed as well. The correct Maven
|
||||
artifacts can be found for every version of MapR at http://doc.mapr.com
|
||||
|
||||
MapR 3.x
|
||||
```
|
||||
mvn clean package -Pmapr3 -DskipTests
|
||||
```
|
||||
MapR 4.0.x
|
||||
```
|
||||
mvn clean package -Pmapr40 -DskipTests
|
||||
```
|
||||
MapR 4.1
|
||||
```
|
||||
mvn clean package -Pmapr41 -DskipTests
|
||||
```
|
||||
MapR 5.0
|
||||
```
|
||||
mvn clean package -Pmapr50 -DskipTests
|
||||
```
|
||||
Yarn (Hadoop 2.7.x)
|
||||
Available profiles are
|
||||
|
||||
```
|
||||
mvn clean package -Pspark-1.4 -Dspark.version=1.4.1 -Dhadoop.version=2.7.0 -Phadoop-2.6 -Pyarn -DskipTests
|
||||
```
|
||||
Yarn (Hadoop 2.6.x)
|
||||
|
||||
```
|
||||
mvn clean package -Pspark-1.1 -Dhadoop.version=2.6.0 -Phadoop-2.6 -Pyarn -DskipTests
|
||||
```
|
||||
Yarn (Hadoop 2.4.x)
|
||||
|
||||
```
|
||||
mvn clean package -Pspark-1.1 -Dhadoop.version=2.4.0 -Phadoop-2.4 -Pyarn -DskipTests
|
||||
```
|
||||
Yarn (Hadoop 2.3.x)
|
||||
|
||||
```
|
||||
mvn clean package -Pspark-1.1 -Dhadoop.version=2.3.0 -Phadoop-2.3 -Pyarn -DskipTests
|
||||
```
|
||||
Yarn (Hadoop 2.2.x)
|
||||
|
||||
```
|
||||
mvn clean package -Pspark-1.1 -Dhadoop.version=2.2.0 -Phadoop-2.2 -Pyarn -DskipTests
|
||||
-Pmapr3
|
||||
-Pmapr40
|
||||
-Pmapr41
|
||||
-Pmapr50
|
||||
```
|
||||
|
||||
Ignite (1.1.0-incubating and later)
|
||||
|
||||
Here're some examples:
|
||||
|
||||
```
|
||||
# basic build
|
||||
mvn clean package -Pspark-1.5 -Phadoop-2.4 -Pyarn -Ppyspark
|
||||
|
||||
# spark-cassandra integration
|
||||
mvn clean package -Pcassandra-spark-1.5 -Dhadoop.version=2.6.0 -Phadoop-2.6 -DskipTests
|
||||
|
||||
# with CDH
|
||||
mvn clean package -Pspark-1.2 -Dhadoop.version=2.5.0-cdh5.3.0 -Phadoop-2.4 -Pvendor-repo -DskipTests
|
||||
|
||||
# with MapR
|
||||
mvn clean package -Pspark-1.5 -Pmapr50 -DskipTests
|
||||
```
|
||||
|
||||
|
||||
#### Ignite Interpreter
|
||||
|
||||
```
|
||||
mvn clean package -Dignite.version=1.1.0-incubating -DskipTests
|
||||
```
|
||||
|
||||
Spark-Cassandra integration (Spark 1.1.x)
|
||||
```
|
||||
mvn clean package -Pcassandra-spark-1.1 -Dhadoop.version=2.6.0 -Phadoop-2.6 -DskipTests
|
||||
```
|
||||
|
||||
Spark-Cassandra integration (Spark 1.2.x)
|
||||
```
|
||||
mvn clean package -Pcassandra-spark-1.2 -Dhadoop.version=2.6.0 -Phadoop-2.6 -DskipTests
|
||||
```
|
||||
|
||||
Spark-Cassandra integration (Spark 1.3.x)
|
||||
```
|
||||
mvn clean package -Pcassandra-spark-1.3 -Dhadoop.version=2.6.0 -Phadoop-2.6 -DskipTests
|
||||
```
|
||||
|
||||
Spark-Cassandra integration (Spark 1.4.x)
|
||||
```
|
||||
mvn clean package -Pcassandra-spark-1.4 -Dhadoop.version=2.6.0 -Phadoop-2.6 -DskipTests
|
||||
```
|
||||
|
||||
Spark-Cassandra integration (Spark 1.5.x)
|
||||
```
|
||||
mvn clean package -Pcassandra-spark-1.5 -Dhadoop.version=2.6.0 -Phadoop-2.6 -DskipTests
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Configure
|
||||
If you wish to configure Zeppelin option (like port number), configure the following files:
|
||||
|
|
|
|||
|
|
@ -76,8 +76,6 @@ function addJarInDir(){
|
|||
fi
|
||||
}
|
||||
|
||||
export ZEPPELIN_CLASSPATH
|
||||
|
||||
# Text encoding for
|
||||
# read/write job into files,
|
||||
# receiving/displaying query/result.
|
||||
|
|
|
|||
|
|
@ -31,6 +31,12 @@
|
|||
<description>Server port.</description>
|
||||
</property>
|
||||
|
||||
<property>
|
||||
<name>zeppelin.server.context.path</name>
|
||||
<value>/</value>
|
||||
<description>Context Path of the Web Application</description>
|
||||
</property>
|
||||
|
||||
<property>
|
||||
<name>zeppelin.notebook.dir</name>
|
||||
<value>notebook</value>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
This readme will walk you through building the Zeppelin documentation, which is included here with the Zeppelin source code.
|
||||
|
||||
|
||||
## Build website
|
||||
## Build documentation
|
||||
See https://help.github.com/articles/using-jekyll-with-pages#installing-jekyll
|
||||
|
||||
**tl;dr version:**
|
||||
|
|
@ -36,3 +36,12 @@ See https://help.github.com/articles/using-jekyll-with-pages#installing-jekyll
|
|||
## Adding a new page
|
||||
|
||||
rake page name="new-page.md"
|
||||
|
||||
|
||||
|
||||
## Bumping up version
|
||||
|
||||
* `BASE_PATH` property in _config.yml
|
||||
* `ZEPPELIN <small>([VERSION])</small>` in _includes/themes/zeppelin/_navigation.html
|
||||
|
||||
need to be updated
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ JB :
|
|||
# - Only the following values are falsy: ["", null, false]
|
||||
# - When setting BASE_PATH it must be a valid url.
|
||||
# This means always setting the protocol (http|https) or prefixing with "/"
|
||||
BASE_PATH : false
|
||||
BASE_PATH : /docs/0.6.0-incubating-SNAPSHOT
|
||||
|
||||
# By default, the asset_path is automatically defined relative to BASE_PATH plus the enabled theme.
|
||||
# ex: [BASE_PATH]/assets/themes/[THEME-NAME]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<div id="menu" class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
|
|
@ -7,21 +7,75 @@
|
|||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="/">
|
||||
<a class="navbar-brand" href="{{BASE_PATH}}">
|
||||
<img src="/assets/themes/zeppelin/img/zeppelin_logo.png" width="50" alt="I'm zeppelin">
|
||||
Zeppelin <small>(0.6.0-incubating-SNAPSHOT)</small>
|
||||
<span style="vertical-align:middle">Zeppelin</span>
|
||||
<span style="vertical-align:baseline"><small>(0.6.0-incubating-SNAPSHOT)</small></span>
|
||||
</a>
|
||||
</div>
|
||||
<nav class="navbar-collapse collapse" role="navigation">
|
||||
<ul class="nav navbar-nav">
|
||||
{% assign pages_list = site.pages %}
|
||||
{% assign group = 'nav-left' %}
|
||||
{% include JB/pages_list %}
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
{% assign pages_list = site.pages %}
|
||||
{% assign group = 'nav-right' %}
|
||||
{% include JB/pages_list %}
|
||||
<li>
|
||||
<a href="#" data-toggle="dropdown" class="dropdown-toggle">Quick Start <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<!-- li><span><b>Overview</b><span></li -->
|
||||
<li><a href="{{BASE_PATH}}/index.html">Overview</a></li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<!-- li><span><b>Install</b><span></li -->
|
||||
<li><a href="{{BASE_PATH}}/install/install.html">Install</a></li>
|
||||
<li><a href="{{BASE_PATH}}/install/yarn_install.html">YARN Install</a></li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<!-- li><span><b>Tutorial</b><span></li -->
|
||||
<li><a href="{{BASE_PATH}}/tutorial/tutorial.html">Tutorial</a></li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<!-- li><span><b>Guide</b><span></li -->
|
||||
<li><a href="{{BASE_PATH}}/manual/dynamicform.html">Dynamic Form</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" data-toggle="dropdown" class="dropdown-toggle">Interpreter <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{{BASE_PATH}}/interpreter/cassandra.html">Cassandra</a></li>
|
||||
<li><a href="{{BASE_PATH}}/interpreter/flink.html">Flink</a></li>
|
||||
<li><a href="{{BASE_PATH}}/interpreter/geode.html">Geode</a></li>
|
||||
<li><a href="{{BASE_PATH}}/pleasecontribute.html">Hive</a></li>
|
||||
<li><a href="{{BASE_PATH}}/interpreter/ignite.html">Ignite</a></li>
|
||||
<li><a href="{{BASE_PATH}}/interpreter/lens.html">Lens</a></li>
|
||||
<li><a href="{{BASE_PATH}}/interpreter/markdown.html">Markdown</a></li>
|
||||
<li><a href="{{BASE_PATH}}/interpreter/postgresql.html">Postgresql, hawq</a></li>
|
||||
<li><a href="{{BASE_PATH}}/pleasecontribute.html">Shell</a></li>
|
||||
<li><a href="{{BASE_PATH}}/interpreter/spark.html">Spark</a></li>
|
||||
<li><a href="{{BASE_PATH}}/pleasecontribute.html">Tajo</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" data-toggle="dropdown" class="dropdown-toggle">Display System <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{{BASE_PATH}}/displaysystem/display.html">Text</a></li>
|
||||
<li><a href="{{BASE_PATH}}/displaysystem/display.html#html">Html</a></li>
|
||||
<li><a href="{{BASE_PATH}}/displaysystem/table.html">Table</a></li>
|
||||
<li><a href="{{BASE_PATH}}/displaysystem/angular.html">Angular</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" data-toggle="dropdown" class="dropdown-toggle">More <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<!-- li><span><b>Manual</b><span></li -->
|
||||
<li><a href="{{BASE_PATH}}/manual/notebookashomepage.html">Notebook as Homepage</a></li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<!-- li><span><b>Notebook Storage</b><span></li -->
|
||||
<li><a href="{{BASE_PATH}}/storage/storage.html">S3 Storage</a></li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<!-- li><span><b>REST API</b><span></li -->
|
||||
<li><a href="{{BASE_PATH}}/rest-api/rest-interpreter.html">Interpreter API</a></li>
|
||||
<li><a href="{{BASE_PATH}}/rest-api/rest-notebook.html">Notebook API</a></li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<!-- li><span><b>Development</b><span></li -->
|
||||
<li><a href="{{BASE_PATH}}/development/writingzeppelininterpreter.html">Writing Zeppelin Interpreter</a></li>
|
||||
<li><a href="{{BASE_PATH}}/development/howtocontribute.html">How to contribute (code)</a></li>
|
||||
<li><a href="{{BASE_PATH}}/development/howtocontributewebsite.html">How to contribute (website)</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav><!--/.navbar-collapse -->
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,47 +7,57 @@ body {
|
|||
}
|
||||
|
||||
.jumbotron {
|
||||
background-color: #3071a9;
|
||||
background: #3071a9;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
padding: 12px 12px;
|
||||
padding-top: 15px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
background-color:#3071a9;
|
||||
border-bottom:0px;
|
||||
height: 50px;
|
||||
background: #3071a9;
|
||||
border-bottom: 0px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-nav > li > a {
|
||||
color: #ffffff;
|
||||
background-color:#3071a9;
|
||||
color: white;
|
||||
background: #3071a9;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-nav > li > a:hover,
|
||||
.navbar-inverse .navbar-nav > li > a:hover,
|
||||
.navbar-inverse .navbar-nav > li > a:focus {
|
||||
color: #ffffff;
|
||||
background-color: #2C6094;
|
||||
color: white !important;
|
||||
background: #2C6094 !important;
|
||||
}
|
||||
.navbar-inverse .navbar-nav > li > a.active:hover,
|
||||
|
||||
.navbar-inverse .navbar-collapse.in .navbar-nav .dropdown-menu > li > a:hover,
|
||||
.navbar-inverse .navbar-collapse.in .navbar-nav .dropdown-menu > li > a:focus {
|
||||
color: white !important;
|
||||
background: #2C6094 !important;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-collapse.in .navbar-nav .dropdown-menu > li > a {
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-collapse.in .navbar-nav .divider {
|
||||
background: #286090;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-nav > li > a.active:hover,
|
||||
.navbar-inverse .navbar-nav > li > a.active:focus {
|
||||
text-decoration: none;
|
||||
background-color: #265380;
|
||||
background: #265380;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-nav > li > a.active {
|
||||
background-color: #265380;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-brand:hover,
|
||||
.navbar-inverse .navbar-brand:focus {
|
||||
background: #265380;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-brand {
|
||||
color: #fff;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
|
@ -55,12 +65,12 @@ body {
|
|||
.navbar-inverse .navbar-collapse,
|
||||
.navbar-inverse .navbar-form {
|
||||
border-color: #265380;
|
||||
background-color: #3071a9;
|
||||
background: #3071a9;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.navbar-collapse.in {
|
||||
box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.4);
|
||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.bigFingerButton {
|
||||
|
|
@ -72,7 +82,7 @@ body {
|
|||
}
|
||||
|
||||
.bigFingerButton {
|
||||
margin-right: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-toggle {
|
||||
|
|
@ -82,14 +92,13 @@ body {
|
|||
.navbar-inverse .navbar-toggle:hover,
|
||||
.navbar-inverse .navbar-toggle:focus {
|
||||
border-color: #265380;
|
||||
background-color: #265380;
|
||||
background: #265380;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-toggle:focus {
|
||||
outline-width: 0px;
|
||||
outline-width: 0;
|
||||
}
|
||||
|
||||
|
||||
/* CUSTOMIZE THE CAROUSEL
|
||||
-------------------------------------------------- */
|
||||
|
||||
|
|
@ -107,6 +116,7 @@ body {
|
|||
.carousel .item {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.carousel-control {
|
||||
background-image: none !important;
|
||||
}
|
||||
|
|
@ -118,10 +128,12 @@ body {
|
|||
min-width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.carousel-indicators {
|
||||
margin-top:30px;
|
||||
margin-bottom:0px;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.carousel-indicators {
|
||||
margin-bottom: -60px;
|
||||
|
|
@ -131,145 +143,273 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.jumbotron h1,
|
||||
.jumbotron p {
|
||||
color: #fff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.jumbotron .thumbnail {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.jumbotron.small {
|
||||
padding: 0 0 0 0;
|
||||
color : #ffffff;
|
||||
padding: 0 0 0 0;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.jumbotron.small .title{
|
||||
float : left;
|
||||
font-weight : bold;
|
||||
font-size : 20px;
|
||||
height : 30px;
|
||||
margin-right: 20px;
|
||||
float: left;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
height: 30px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.jumbotron.small .subtitle{
|
||||
font-size : 14px;
|
||||
height : 30px;
|
||||
vertical-align:text-bottom;
|
||||
padding-top:7px;
|
||||
font-size: 14px;
|
||||
height: 30px;
|
||||
vertical-align:text-bottom;
|
||||
padding-top:7px;
|
||||
}
|
||||
|
||||
.jumbotron.small .description{
|
||||
margin-top: 7px;
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* screenshot img inside of doc */
|
||||
.screenshot {
|
||||
width : 800px;
|
||||
width: 800px;
|
||||
}
|
||||
|
||||
/* Table on the index page */
|
||||
.table-container {
|
||||
position: absolute;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.table-stack {
|
||||
/* border: 1px solid #6371a9;*/
|
||||
width:200px; padding: 5px 5px 5px 5px;
|
||||
width: 200px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.table-stack table {
|
||||
width:100%
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.table-stack tr td{
|
||||
border: 1px solid #FFFFFF;
|
||||
height : 40px;
|
||||
background-color : #6371a9;
|
||||
color : #FFFFFF;
|
||||
border: 1px solid white;
|
||||
height: 40px;
|
||||
background: #6371a9;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.table-stack .gray {
|
||||
background-color:#DDDDDD;
|
||||
color:#777777;
|
||||
background:#DDDDDD;
|
||||
color:#777777;
|
||||
}
|
||||
|
||||
/* Table for property */
|
||||
.table-configuration {
|
||||
width : 800px;
|
||||
<<<<<<< HEAD
|
||||
width : 100%;
|
||||
border : 1px solid gray;
|
||||
=======
|
||||
width: 800px;
|
||||
border: 1px solid gray;
|
||||
>>>>>>> PR_TOOL_MERGE_PR_483
|
||||
}
|
||||
.table-configuration tr td {
|
||||
border : 1px solid gray;
|
||||
padding : 5px 5px 5px 5px;
|
||||
border: 1px solid gray;
|
||||
padding: 5px;
|
||||
}
|
||||
.table-configuration tr th {
|
||||
border : 1px solid gray;
|
||||
padding : 5px 5px 5px 5px;
|
||||
background-color: #B0C4DE;
|
||||
border: 1px solid gray;
|
||||
padding: 5px;
|
||||
background: #B0C4DE;
|
||||
}
|
||||
|
||||
|
||||
.rotate270 {
|
||||
width:15px;padding:10px 0px 0px 0px;
|
||||
-webkit-transform: rotate(270deg);
|
||||
-moz-transform: rotate(270deg);
|
||||
-ms-transform: rotate(270deg);
|
||||
-o-transform: rotate(270deg);
|
||||
transform: rotate(270deg);
|
||||
width: 15px;
|
||||
padding: 10px 0 0 0;
|
||||
-webkit-transform: rotate(270deg);
|
||||
-moz-transform: rotate(270deg);
|
||||
-ms-transform: rotate(270deg);
|
||||
-o-transform: rotate(270deg);
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Custom container */
|
||||
<<<<<<< HEAD
|
||||
/* <a> */
|
||||
.container a {
|
||||
color: #4183C4; }
|
||||
a.absent {
|
||||
color: #cc0000; }
|
||||
a.anchor {
|
||||
display: block;
|
||||
padding-left: 30px;
|
||||
margin-left: -30px;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
/* <hn> */
|
||||
.container h1, h2, h3, h4, h5, h6 {
|
||||
margin: 20px 0 10px;
|
||||
padding: 0;
|
||||
font-weight: bold;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
cursor: text;
|
||||
position: relative; }
|
||||
.container h1 {
|
||||
font-size: 30px;
|
||||
color: black; }
|
||||
.container h2 {
|
||||
font-size: 28px;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 1px solid #E5E5E5;}
|
||||
.container h3 {
|
||||
font-size: 22px;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 1px solid #E5E5E5;}
|
||||
.container h4 {
|
||||
font-size: 18px; }
|
||||
.container h5 {
|
||||
font-size: 14px; }
|
||||
.container h6 {
|
||||
font-size: 14px;
|
||||
color: #777777;}
|
||||
|
||||
/* <li, ul, ol> */
|
||||
.container li {
|
||||
margin: 0; }
|
||||
.container li p.first {
|
||||
display: inline-block;}
|
||||
.container ul :first-child, ol :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* <table> */
|
||||
.container table {
|
||||
width : 100%;
|
||||
padding: 0;
|
||||
border-collapse: collapse; }
|
||||
.container table tr {
|
||||
border-top: 1px solid #cccccc;
|
||||
background-color: white;
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
.container table tr th {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
border: 1px solid #cccccc;
|
||||
margin: 0;
|
||||
padding: 6px 13px; }
|
||||
.container table tr td {
|
||||
border: 1px solid #cccccc;
|
||||
margin: 0;
|
||||
padding: 6px 13px;
|
||||
}
|
||||
|
||||
/* <code> */
|
||||
.container code{
|
||||
color:#000000;
|
||||
font-size: 90%;
|
||||
font-family: "Menlo", "Lucida Console", monospace;
|
||||
background-color: #f8f8f8;
|
||||
border: 1px solid #cccccc;
|
||||
}
|
||||
|
||||
/* <pre> */
|
||||
.container pre {
|
||||
background-color: #f8f8f8;
|
||||
border: 1px solid #cccccc;
|
||||
line-height: 19px;
|
||||
overflow: auto;
|
||||
padding: 6px 10px;
|
||||
border-radius: 3px;}
|
||||
.container pre code {
|
||||
font-size: 95%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
white-space: pre;
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* <blockquote> */
|
||||
.container blockquote {
|
||||
border-left: 4px solid #dddddd;
|
||||
padding: 0 15px;
|
||||
color: #777777; }
|
||||
.container blockquote > :first-child {
|
||||
margin-top: 0; }
|
||||
.container blockquote > :last-child {
|
||||
margin-bottom: 0; }
|
||||
.container blockquote p{
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* <p>, <blockquote>, <table>, <pre>, <img> margin */
|
||||
.container p, blockquote, table, pre, img {
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
=======
|
||||
>>>>>>> PR_TOOL_MERGE_PR_483
|
||||
.container-narrow {
|
||||
margin: 0 auto;
|
||||
/* max-width: 960px; */
|
||||
}
|
||||
|
||||
.container-narrow > hr {
|
||||
margin: 30px 0; }
|
||||
margin: 30px 0;
|
||||
}
|
||||
|
||||
/* posts index */
|
||||
.post > h3.title {
|
||||
position: relative;
|
||||
padding-top: 10px; }
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.post > h3.title span.date {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
font-size: 0.9em; }
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.post > .more {
|
||||
margin: 10px 0;
|
||||
text-align: left; }
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* post-full*/
|
||||
.post-full .date {
|
||||
margin-bottom: 20px;
|
||||
font-weight: bold; }
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* tag_box */
|
||||
.tag_box {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
overflow: hidden; }
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tag_box li {
|
||||
line-height: 28px; }
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.tag_box li i {
|
||||
opacity: 0.9; }
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.tag_box.inline li {
|
||||
float: left; }
|
||||
float: left;
|
||||
}
|
||||
|
||||
.tag_box a {
|
||||
padding: 3px 6px;
|
||||
|
|
@ -278,76 +418,105 @@ body {
|
|||
color: #555;
|
||||
border-radius: 3px;
|
||||
text-decoration: none;
|
||||
border: 1px dashed #cccccc; }
|
||||
border: 1px dashed #cccccc;
|
||||
}
|
||||
|
||||
.tag_box a span {
|
||||
vertical-align: super;
|
||||
font-size: 0.8em; }
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.tag_box a:hover {
|
||||
background-color: #e5e5e5; }
|
||||
background: #e5e5e5;
|
||||
}
|
||||
|
||||
.tag_box a.active {
|
||||
background: #57A957;
|
||||
border: 1px solid #4c964d;
|
||||
color: #FFF; }
|
||||
|
||||
color: white;
|
||||
}
|
||||
|
||||
.jumbotron h1 {
|
||||
font-family: 'Patua One', cursive; }
|
||||
font-family: 'Patua One', cursive;
|
||||
}
|
||||
|
||||
.jumbotron small {
|
||||
font-size: 60%;
|
||||
color: #FFF;}
|
||||
font-size: 60%;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
font-family: 'Patua One', cursive;
|
||||
font-family: 'Patua One', cursive;
|
||||
}
|
||||
|
||||
.navbar-brand small {
|
||||
font-size: 14px;
|
||||
font-family: 'Helvetica Neue', Helvetica;
|
||||
color: #FFF; }
|
||||
font-size: 14px;
|
||||
font-family: 'Helvetica Neue', Helvetica;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.navbar-collapse.collapse {
|
||||
max-height: 50px;}
|
||||
max-height: 50px;
|
||||
}
|
||||
|
||||
#apache .caret {
|
||||
margin-left: 4px;
|
||||
border-top-color: #FFF;
|
||||
margin-left: 4px;
|
||||
border-top-color: white;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-nav > .open > a,
|
||||
.navbar-inverse .navbar-nav > .open > a:hover,
|
||||
.navbar-inverse .navbar-nav > .open > a:focus {
|
||||
color: #ffffff;
|
||||
background-color: #286090;
|
||||
color: white;
|
||||
background: #286090;
|
||||
}
|
||||
|
||||
/* Custom, iPhone Retina */
|
||||
@media only screen and (max-width : 480px) {
|
||||
/* Custom, iPhone Retina */
|
||||
@media only screen and (max-width: 480px) {
|
||||
.jumbotron h1 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navbar-brand small {
|
||||
display: none;
|
||||
color: #FFF;
|
||||
display: none;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width : 768px) {
|
||||
@media only screen and (max-width: 768px) {
|
||||
.navbar .navbar-brand {
|
||||
padding-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen
|
||||
and (min-width : 768px)
|
||||
and (max-width : 1024px) {
|
||||
and (min-width: 768px)
|
||||
and (max-width: 1024px) {
|
||||
.navbar-brand small {
|
||||
display: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navbar-collapse.collapse {
|
||||
padding-right: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* docs dropdown menu */
|
||||
#menu .dropdown-menu li span {
|
||||
padding: 3px 10px 10px 10px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#menu .caret {
|
||||
border-top-color: white;
|
||||
border-bottom-color: white;
|
||||
}
|
||||
|
||||
#menu .open .caret {
|
||||
border-top-color: #428bca;
|
||||
border-bottom-color: #428bca;
|
||||
}
|
||||
|
||||
#menu .navbar-brand {
|
||||
margin-right: 50px;
|
||||
}
|
||||
|
|
|
|||
BIN
docs/assets/themes/zeppelin/img/docs-img/markdown-example.png
Normal file
BIN
docs/assets/themes/zeppelin/img/docs-img/markdown-example.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
|
|
@ -25,7 +25,7 @@ Zeppelin Interpreter is a language backend. For example to use scala code in Zep
|
|||
Every Interpreter belongs to an InterpreterGroup. InterpreterGroup is a unit of start/stop interpreter.
|
||||
Interpreters in the same InterpreterGroup can reference each other. For example, SparkSqlInterpreter can reference SparkInterpreter to get SparkContext from it while they're in the same group.
|
||||
|
||||
<img class="img-responsive" style="width:50%; border: 1px solid #ecf0f1;" height="auto" src="../../assets/themes/zeppelin/img/interpreter.png" />
|
||||
<img class="img-responsive" style="width:50%; border: 1px solid #ecf0f1;" height="auto" src="/assets/themes/zeppelin/img/interpreter.png" />
|
||||
|
||||
All Interpreters in the same interpreter group are launched in a single, separate JVM process. The Interpreter communicates with Zeppelin engine via thrift.
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ Therefore, you can not only update scope variable from your interpreter but also
|
|||
#### Print AngularJS view
|
||||
|
||||
To use angular display system, your output should starts with "%angular".
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/display_angular.png" width=600px />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/display_angular.png" width=600px />
|
||||
|
||||
Note that display system is backend independent.
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ z.angularUnbindGlobal(String name)
|
|||
|
||||
In the example, let's bind "world" variable 'name'. Then you can see AngularJs view are updated immediately.
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/display_angular1.png" width=600px />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/display_angular1.png" width=600px />
|
||||
|
||||
|
||||
<br />
|
||||
|
|
@ -91,8 +91,8 @@ z.angularUnwatchGlobal(String name)
|
|||
Let's make an button, that increment 'run' variable by 1 when it is clicked.
|
||||
z.angularBind("run", 0) will initialize 'run' to zero. And then register watcher of 'run'.
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/display_angular2.png" width=600px />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/display_angular2.png" width=600px />
|
||||
|
||||
After clicked button, you'll see both 'run' and numWatched are increased by 1
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/display_angular3.png" width=600px />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/display_angular3.png" width=600px />
|
||||
|
|
|
|||
|
|
@ -27,11 +27,11 @@ limitations under the License.
|
|||
|
||||
Zeppelin prints output of language backend in text, by default.
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/display_text.png" />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/display_text.png" />
|
||||
|
||||
You can explicitly say you're using text display system.
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/display_text1.png" />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/display_text1.png" />
|
||||
|
||||
Note that display system is backend independent.
|
||||
|
||||
|
|
@ -42,4 +42,4 @@ Note that display system is backend independent.
|
|||
|
||||
With '%html' directive, Zeppelin treats your output as html
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/display_html.png" />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/display_html.png" />
|
||||
|
|
|
|||
|
|
@ -24,14 +24,14 @@ limitations under the License.
|
|||
|
||||
If you have data that row seprated by '\n' (newline) and column separated by '\t' (tab) with first row as header row, for example
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/display_table.png" />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/display_table.png" />
|
||||
|
||||
You can simply use %table display system to leverage Zeppelin's built in visualization.
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/display_table1.png" />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/display_table1.png" />
|
||||
|
||||
Note that display system is backend independent.
|
||||
|
||||
If table contents start with %html, it is interpreted as an HTML.
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/display_table_html.png" />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/display_table_html.png" />
|
||||
|
|
|
|||
|
|
@ -35,14 +35,14 @@ limitations under the License.
|
|||
* [cassandra](./interpreter/cassandra.html)
|
||||
* [flink](./interpreter/flink.html)
|
||||
* [geode](./interpreter/geode.html)
|
||||
* [hive](../pleasecontribute.html)
|
||||
* [hive](./pleasecontribute.html)
|
||||
* [ignite](./interpreter/ignite.html)
|
||||
* [lens](./interpreter/lens.html)
|
||||
* [md](../pleasecontribute.html)
|
||||
* [md](./interpreter/markdown.html)
|
||||
* [postgresql, hawq](./interpreter/postgresql.html)
|
||||
* [sh](../pleasecontribute.html)
|
||||
* [sh](./pleasecontribute.html)
|
||||
* [spark](./interpreter/spark.html)
|
||||
* [tajo](../pleasecontribute.html)
|
||||
* [tajo](./pleasecontribute.html)
|
||||
|
||||
### Storage
|
||||
* [S3 Storage](./storage/storage.html)
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ limitations under the License.
|
|||
</ul>
|
||||
|
||||
</div>
|
||||
<div class="col-md-7"><img class="img-responsive" style="border: 1px solid #ecf0f1;" height="auto" src="assets/themes/zeppelin/img/notebook.png" /></div>
|
||||
<div class="col-md-7"><img class="img-responsive" style="border: 1px solid #ecf0f1;" height="auto" src="/assets/themes/zeppelin/img/notebook.png" /></div>
|
||||
</div>
|
||||
|
||||
|
||||
|
|
@ -44,17 +44,16 @@ limitations under the License.
|
|||
Zeppelin interpreter concept allows any language/data-processing-backend to be plugged into Zeppelin.
|
||||
Currently Zeppelin supports many interpreters such as Scala(with Apache Spark), Python(with Apache Spark), SparkSQL, Hive, Markdown and Shell.
|
||||
|
||||
<img class="img-responsive" src="assets/themes/zeppelin/img/screenshots/multiple_language_backend.png" />
|
||||
<img class="img-responsive" src="/assets/themes/zeppelin/img/screenshots/multiple_language_backend.png" />
|
||||
|
||||
Adding new language-backend is really simple. Learn [how to write a zeppelin interpreter](./development/writingzeppelininterpreter.html).
|
||||
|
||||
|
||||
<br />
|
||||
### Apache Spark integration
|
||||
|
||||
Zeppelin provides built-in Apache Spark integration. You don't need to build a separate module, plugin or library for it.
|
||||
|
||||
<img src="assets/themes/zeppelin/img/spark_logo.jpg" width="80px" />
|
||||
<img src="/assets/themes/zeppelin/img/spark_logo.jpg" width="80px" />
|
||||
|
||||
Zeppelin's Spark integration provides
|
||||
|
||||
|
|
@ -69,10 +68,10 @@ Some basic charts are already included in Zeppelin. Visualizations are not limit
|
|||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<img class="img-responsive" src="./assets/themes/zeppelin/img/graph1.png" />
|
||||
<img class="img-responsive" src="/assets/themes/zeppelin/img/graph1.png" />
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<img class="img-responsive" src="./assets/themes/zeppelin/img/graph2.png" />
|
||||
<img class="img-responsive" src="/assets/themes/zeppelin/img/graph2.png" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -82,7 +81,7 @@ With simple drag and drop Zeppelin aggeregates the values and display them in pi
|
|||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<img class="img-responsive" src="./assets/themes/zeppelin/img/screenshots/pivot.png" />
|
||||
<img class="img-responsive" src="/assets/themes/zeppelin/img/screenshots/pivot.png" />
|
||||
</div>
|
||||
</div>
|
||||
Learn more about Zeppelin's Display system. ( [text](./displaysystem/display.html), [html](./displaysystem/display.html#html), [table](./displaysystem/table.html), [angular](./displaysystem/angular.html) )
|
||||
|
|
@ -93,7 +92,7 @@ Learn more about Zeppelin's Display system. ( [text](./displaysystem/display.htm
|
|||
|
||||
Zeppelin can dynamically create some input forms into your notebook.
|
||||
|
||||
<img class="img-responsive" src="./assets/themes/zeppelin/img/screenshots/form_input.png" />
|
||||
<img class="img-responsive" src="/assets/themes/zeppelin/img/screenshots/form_input.png" />
|
||||
|
||||
Learn more about [Dynamic Forms](./manual/dynamicform.html).
|
||||
|
||||
|
|
@ -103,7 +102,7 @@ Learn more about [Dynamic Forms](./manual/dynamicform.html).
|
|||
|
||||
Notebook URL can be shared among collaborators. Zeppelin can then broadcast any changes in realtime, just like the collaboration in Google docs.
|
||||
|
||||
<img src="./assets/themes/zeppelin/img/screenshots/collaboration.png" />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/collaboration.png" />
|
||||
|
||||
<br />
|
||||
### Publish
|
||||
|
|
@ -112,7 +111,7 @@ Notebook URL can be shared among collaborators. Zeppelin can then broadcast any
|
|||
This way, you can easily embed it as an iframe inside of your website.</p>
|
||||
|
||||
<div class="row">
|
||||
<img class="img-responsive center-block" src="./assets/themes/zeppelin/img/screenshots/publish.png" />
|
||||
<img class="img-responsive center-block" src="/assets/themes/zeppelin/img/screenshots/publish.png" />
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
|
|
|||
|
|
@ -21,46 +21,14 @@ limitations under the License.
|
|||
|
||||
|
||||
|
||||
## Build
|
||||
## From binary package
|
||||
|
||||
#### Prerequisites
|
||||
Download latest binary package from [Download](../download.html).
|
||||
|
||||
* Java 1.7
|
||||
* None root account
|
||||
* Apache Maven
|
||||
|
||||
Build tested on OSX, CentOS 6.
|
||||
|
||||
Checkout source code from [https://github.com/apache/incubator-zeppelin](https://github.com/apache/incubator-zeppelin)
|
||||
|
||||
#### Local mode
|
||||
|
||||
```
|
||||
mvn install -DskipTests
|
||||
```
|
||||
|
||||
#### Cluster mode
|
||||
|
||||
```
|
||||
mvn install -DskipTests -Dspark.version=1.1.0 -Dhadoop.version=2.2.0
|
||||
```
|
||||
|
||||
Change spark.version and hadoop.version to your cluster's one.
|
||||
|
||||
#### Custom built Spark
|
||||
|
||||
Note that is you uses custom build spark, you need build Zeppelin with custome built spark artifact. To do that, deploy spark artifact to local maven repository using
|
||||
|
||||
```
|
||||
sbt/sbt publish-local
|
||||
```
|
||||
|
||||
and then build Zeppelin with your custom built Spark
|
||||
|
||||
```
|
||||
mvn install -DskipTests -Dspark.version=1.1.0-Custom -Dhadoop.version=2.2.0
|
||||
```
|
||||
## Build from source
|
||||
|
||||
Check instructions in [README](https://github.com/apache/incubator-zeppelin/blob/master/README.md) to build from source.
|
||||
|
||||
|
||||
|
||||
|
|
@ -80,19 +48,141 @@ Configuration can be done by both environment variable(conf/zeppelin-env.sh) and
|
|||
<td>ZEPPELIN_PORT</td>
|
||||
<td>zeppelin.server.port</td>
|
||||
<td>8080</td>
|
||||
<td>Zeppelin server port. Note that port+1 is used for web socket</td>
|
||||
<td>Zeppelin server port.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_MEM</td>
|
||||
<td>N/A</td>
|
||||
<td>-Xmx1024m -XX:MaxPermSize=512m</td>
|
||||
<td>JVM mem options</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_INTP_MEM</td>
|
||||
<td>N/A</td>
|
||||
<td>ZEPPELIN_MEM</td>
|
||||
<td>JVM mem options for interpreter process</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_JAVA_OPTS</td>
|
||||
<td>N/A</td>
|
||||
<td></td>
|
||||
<td>JVM Options</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_ALLOWED_ORIGINS</td>
|
||||
<td>zeppelin.server.allowed.origins</td>
|
||||
<td>*</td>
|
||||
<td>Allows a way to specify a ',' separated list of allowed origins for rest and websockets. i.e. http://localhost:8080</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_SERVER_CONTEXT_PATH</td>
|
||||
<td>zeppelin.server.context.path</td>
|
||||
<td>/</td>
|
||||
<td>Context Path of the Web Application</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_SSL</td>
|
||||
<td>zeppelin.ssl</td>
|
||||
<td>false</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_SSL_CLIENT_AUTH</td>
|
||||
<td>zeppelin.ssl.client.auth</td>
|
||||
<td>false</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_SSL_KEYSTORE_PATH</td>
|
||||
<td>zeppelin.ssl.keystore.path</td>
|
||||
<td>keystore</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_SSL_KEYSTORE_TYPE</td>
|
||||
<td>zeppelin.ssl.keystore.type</td>
|
||||
<td>JKS</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_SSL_KEYSTORE_PASSWORD</td>
|
||||
<td>zeppelin.ssl.keystore.password</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_SSL_KEY_MANAGER_PASSWORD</td>
|
||||
<td>zeppelin.ssl.key.manager.password</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_SSL_TRUSTSTORE_PATH</td>
|
||||
<td>zeppelin.ssl.truststore.path</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_SSL_TRUSTSTORE_TYPE</td>
|
||||
<td>zeppelin.ssl.truststore.type</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_SSL_TRUSTSTORE_PASSWORD</td>
|
||||
<td>zeppelin.ssl.truststore.password</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_NOTEBOOK_HOMESCREEN</td>
|
||||
<td>zeppelin.notebook.homescreen</td>
|
||||
<td></td>
|
||||
<td>Id of notebook to be displayed in homescreen ex) 2A94M5J1Z</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_NOTEBOOK_HOMESCREEN_HIDE</td>
|
||||
<td>zeppelin.notebook.homescreen.hide</td>
|
||||
<td>false</td>
|
||||
<td>hide homescreen notebook from list when this value set to "true"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_NOTEBOOK_DIR</td>
|
||||
<td>zeppelin.notebook.dir</td>
|
||||
<td>notebook</td>
|
||||
<td>Where notebook file is saved</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_NOTEBOOK_S3_BUCKET</td>
|
||||
<td>zeppelin.notebook.s3.bucket</td>
|
||||
<td>zeppelin</td>
|
||||
<td>Bucket where notebook saved</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_NOTEBOOK_S3_USER</td>
|
||||
<td>zeppelin.notebook.s3.user</td>
|
||||
<td>user</td>
|
||||
<td>User in bucket where notebook saved. For example bucket/user/notebook/2A94M5J1Z/note.json</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_NOTEBOOK_STORAGE</td>
|
||||
<td>zeppelin.notebook.storage</td>
|
||||
<td>org.apache.zeppelin.notebook.repo.VFSNotebookRepo</td>
|
||||
<td>Comma separated list of notebook storage</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_NOTEBOOK_RELOAD_FROM_STORAGE</td>
|
||||
<td>zeppelin.notebook.reloadAllNotesFromStorage</td>
|
||||
<td>false</td>
|
||||
<td>Notebook list and contents will be always loaded from repository if set true. If set false, modified notebooks or new notebooks added on file system level won't be reflected on Zeppelin till user restarts Zeppelin.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_INTERPRETERS</td>
|
||||
<td>zeppelin.interpreters</td>
|
||||
<description></description>
|
||||
<td>org.apache.zeppelin.spark.SparkInterpreter,<br />org.apache.zeppelin.spark.PySparkInterpreter,<br />org.apache.zeppelin.spark.SparkSqlInterpreter,<br />org.apache.zeppelin.spark.DepInterpreter,<br />org.apache.zeppelin.markdown.Markdown,<br />org.apache.zeppelin.shell.ShellInterpreter,<br />org.apache.zeppelin.hive.HiveInterpreter</td>
|
||||
<td>org.apache.zeppelin.spark.SparkInterpreter,<br />org.apache.zeppelin.spark.PySparkInterpreter,<br />org.apache.zeppelin.spark.SparkSqlInterpreter,<br />org.apache.zeppelin.spark.DepInterpreter,<br />org.apache.zeppelin.markdown.Markdown,<br />org.apache.zeppelin.shell.ShellInterpreter,<br />org.apache.zeppelin.hive.HiveInterpreter<br />
|
||||
...
|
||||
</td>
|
||||
<td>Comma separated interpreter configurations [Class]. First interpreter become a default</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
@ -101,19 +191,14 @@ Configuration can be done by both environment variable(conf/zeppelin-env.sh) and
|
|||
<td>interpreter</td>
|
||||
<td>Zeppelin interpreter directory</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MASTER</td>
|
||||
<td></td>
|
||||
<td>N/A</td>
|
||||
<td>Spark master url. eg. spark://master_addr:7077. Leave empty if you want to use local mode</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ZEPPELIN_JAVA_OPTS</td>
|
||||
<td></td>
|
||||
<td>N/A</td>
|
||||
<td>JVM Options</td>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
You'll also need to configure individual interpreter. Information can be found in 'Interpreter' section in this documentation.
|
||||
|
||||
For example [Spark](../interpreter/spark.html).
|
||||
|
||||
<br />
|
||||
## Start/Stop
|
||||
#### Start Zeppelin
|
||||
|
||||
|
|
@ -121,7 +206,6 @@ Configuration can be done by both environment variable(conf/zeppelin-env.sh) and
|
|||
bin/zeppelin-daemon.sh start
|
||||
```
|
||||
After successful start, visit http://localhost:8080 with your web browser.
|
||||
Note that port **8081** also need to be accessible for websocket connection.
|
||||
|
||||
#### Stop Zeppelin
|
||||
|
||||
|
|
|
|||
|
|
@ -30,9 +30,9 @@ group: manual
|
|||
In a notebook, to enable the **Cassandra** interpreter, click on the **Gear** icon and select **Cassandra**
|
||||
|
||||
<center>
|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
</center>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -44,7 +44,7 @@ group: manual
|
|||
To access the interactive help, type **HELP;**
|
||||
|
||||
<center>
|
||||

|
||||

|
||||
</center>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -283,7 +283,7 @@ There is a drop-down menu on the top left corner to expand objects details. On t
|
|||
|
||||
<br/>
|
||||
<center>
|
||||

|
||||

|
||||
</center>
|
||||
|
||||
<hr/>
|
||||
|
|
@ -551,7 +551,7 @@ For this, first go to the **Interpreter** menu and click on the **Create** butto
|
|||
<br/>
|
||||
<br/>
|
||||
<center>
|
||||

|
||||

|
||||
</center>
|
||||
|
||||
In the interpreter creation form, put **cass-instance2** as **Name** and select the **cassandra**
|
||||
|
|
@ -559,7 +559,7 @@ in the interpreter drop-down list
|
|||
<br/>
|
||||
<br/>
|
||||
<center>
|
||||

|
||||

|
||||
</center>
|
||||
|
||||
Click on **Save** to create the new interpreter instance. Now you should be able to see it in the interpreter list.
|
||||
|
|
@ -567,7 +567,7 @@ in the interpreter drop-down list
|
|||
<br/>
|
||||
<br/>
|
||||
<center>
|
||||

|
||||

|
||||
</center>
|
||||
|
||||
Go back to your notebook and click on the **Gear** icon to configure interpreter bindings.
|
||||
|
|
@ -577,7 +577,7 @@ interpreter list instead of the standard **cassandra** instance.
|
|||
<br/>
|
||||
<br/>
|
||||
<center>
|
||||

|
||||

|
||||
</center>
|
||||
|
||||
<hr/>
|
||||
|
|
|
|||
|
|
@ -37,23 +37,23 @@ This interpreter supports the [Geode](http://geode.incubator.apache.org/) [Objec
|
|||
|
||||
This [Video Tutorial](https://www.youtube.com/watch?v=zvzzA9GXu3Q) illustrates some of the features provided by the `Geode Interpreter`.
|
||||
|
||||
### Create Interpreter
|
||||
### Create Interpreter
|
||||
|
||||
By default Zeppelin creates one `Geode/OQL` instance. You can remove it or create more instances.
|
||||
By default Zeppelin creates one `Geode/OQL` instance. You can remove it or create more instances.
|
||||
|
||||
Multiple Geode instances can be created, each configured to the same or different backend Geode cluster. But over time a `Notebook` can have only one Geode interpreter instance `bound`. That means you _can not_ connect to different Geode clusters in the same `Notebook`. This is a known Zeppelin limitation.
|
||||
Multiple Geode instances can be created, each configured to the same or different backend Geode cluster. But over time a `Notebook` can have only one Geode interpreter instance `bound`. That means you _cannot_ connect to different Geode clusters in the same `Notebook`. This is a known Zeppelin limitation.
|
||||
|
||||
To create new Geode instance open the `Interprter` section and click the `+Create` button. Pick a `Name` of your choice and from the `Interpreter` drop-down select `geode`. Then follow the configuration instructions and `Save` the new instance.
|
||||
To create new Geode instance open the `Interpreter` section and click the `+Create` button. Pick a `Name` of your choice and from the `Interpreter` drop-down select `geode`. Then follow the configuration instructions and `Save` the new instance.
|
||||
|
||||
> Note: The `Name` of the instance is used only to distinct the instances while binding them to the `Notebook`. The `Name` is irrelevant inside the `Notebook`. In the `Notebook` you must use `%geode.oql` tag.
|
||||
> Note: The `Name` of the instance is used only to distinguish the instances while binding them to the `Notebook`. The `Name` is irrelevant inside the `Notebook`. In the `Notebook` you must use `%geode.oql` tag.
|
||||
|
||||
### Bind to Notebook
|
||||
In the `Notebook` click on the `settings` icon in the top right corner. The select/deselect the interpreters to be bound with the `Notebook`.
|
||||
|
||||
### Configuration
|
||||
You can modify the configuration of the Geode from the `Interpreter` section. The Geode interpreter express the following properties:
|
||||
You can modify the configuration of the Geode from the `Interpreter` section. The Geode interpreter expresses the following properties:
|
||||
|
||||
|
||||
|
||||
<table class="table-configuration">
|
||||
<tr>
|
||||
<th>Property Name</th>
|
||||
|
|
@ -76,16 +76,16 @@ You can modify the configuration of the Geode from the `Interpreter` section. T
|
|||
<td>1000</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
### How to use
|
||||
|
||||
> *Tip 1: Use (CTRL + .) for OQL auto-completion.*
|
||||
|
||||
> *Tip 2: Alawys start the paragraphs with the full `%geode.oql` prefix tag! The short notation: `%geode` would still be able run the OQL queries but the syntax highlighting and the auto-completions will be disabled.*
|
||||
> *Tip 2: Always start the paragraphs with the full `%geode.oql` prefix tag! The short notation: `%geode` would still be able run the OQL queries but the syntax highlighting and the auto-completions will be disabled.*
|
||||
|
||||
#### Create / Destroy Regions
|
||||
|
||||
The OQL sepecification does not support [Geode Regions](https://cwiki.apache.org/confluence/display/GEODE/Index#Index-MainConceptsandComponents) mutation operations. To `creaate`/`destroy` regions one should use the [GFSH](http://geode-docs.cfapps.io/docs/tools_modules/gfsh/chapter_overview.html) shell tool instead. To wokr this it assumes that the GFSH is colocated with Zeppelin server.
|
||||
The OQL specification does not support [Geode Regions](https://cwiki.apache.org/confluence/display/GEODE/Index#Index-MainConceptsandComponents) mutation operations. To `create`/`destroy` regions one should use the [GFSH](http://geode-docs.cfapps.io/docs/tools_modules/gfsh/chapter_overview.html) shell tool instead. In the following it is assumed that the GFSH is colocated with Zeppelin server.
|
||||
|
||||
```bash
|
||||
%sh
|
||||
|
|
@ -98,26 +98,26 @@ gfsh << EOF
|
|||
destroy region --name=/regionCompany
|
||||
create region --name=regionEmployee --type=REPLICATE
|
||||
create region --name=regionCompany --type=REPLICATE
|
||||
|
||||
|
||||
exit;
|
||||
EOF
|
||||
```
|
||||
|
||||
Above snippet re-creates two regions: `regionEmployee` and `regionCompany`. Note that you have to explicetely specify the locator host and port. The values should match those you have used in the Geode Interpreter configuration. Comprehensive list of [GFSH Commands by Functional Area](http://geode-docs.cfapps.io/docs/tools_modules/gfsh/gfsh_quick_reference.html).
|
||||
Above snippet re-creates two regions: `regionEmployee` and `regionCompany`. Note that you have to explicitly specify the locator host and port. The values should match those you have used in the Geode Interpreter configuration. Comprehensive list of [GFSH Commands by Functional Area](http://geode-docs.cfapps.io/docs/tools_modules/gfsh/gfsh_quick_reference.html).
|
||||
|
||||
#### Basic OQL
|
||||
|
||||
|
||||
```sql
|
||||
%geode.oql
|
||||
SELECT count(*) FROM /regionEmploee
|
||||
```sql
|
||||
%geode.oql
|
||||
SELECT count(*) FROM /regionEmployee
|
||||
```
|
||||
|
||||
OQL `IN` and `SET` filters:
|
||||
|
||||
```sql
|
||||
%geode.oql
|
||||
SELECT * FROM /regionEmployee
|
||||
SELECT * FROM /regionEmployee
|
||||
WHERE companyId IN SET(2) OR lastName IN SET('Tzolov13', 'Tzolov73')
|
||||
```
|
||||
|
||||
|
|
@ -126,15 +126,15 @@ OQL `JOIN` operations
|
|||
```sql
|
||||
%geode.oql
|
||||
SELECT e.employeeId, e.firstName, e.lastName, c.id as companyId, c.companyName, c.address
|
||||
FROM /regionEmployee e, /regionCompany c
|
||||
FROM /regionEmployee e, /regionCompany c
|
||||
WHERE e.companyId = c.id
|
||||
```
|
||||
|
||||
By default the QOL responses contain only the region entry values. To access the keys, query the `EntrySet` instead:
|
||||
By default the QOL responses contain only the region entry values. To access the keys, query the `EntrySet` instead:
|
||||
|
||||
```sql
|
||||
%geode.oql
|
||||
SELECT e.key, e.value.companyId, e.value.email
|
||||
SELECT e.key, e.value.companyId, e.value.email
|
||||
FROM /regionEmployee.entrySet e
|
||||
```
|
||||
Following query will return the EntrySet value as a Blob:
|
||||
|
|
@ -160,7 +160,7 @@ gfsh -e "connect" -e "list members"
|
|||
|
||||
#### Apply Zeppelin Dynamic Forms
|
||||
|
||||
You can leverage [Zepplein Dynamic Form](https://zeppelin.incubator.apache.org/docs/manual/dynamicform.html) inside your OQL queries. You can use both the `text input` and `select form` parametrization features
|
||||
You can leverage [Zeppelin Dynamic Form](../manual/dynamicform.html) inside your OQL queries. You can use both the `text input` and `select form` parameterization features
|
||||
|
||||
```sql
|
||||
%geode.oql
|
||||
|
|
@ -197,7 +197,5 @@ http-service-port=8484
|
|||
start-dev-rest-api=true
|
||||
```
|
||||
|
||||
### Auto-completion
|
||||
The Geode Interpreter provides a basic auto-completion functionality. On `(Ctrl+.)` it list the most relevant suggesntions in a pop-up window.
|
||||
|
||||
|
||||
### Auto-completion
|
||||
The Geode Interpreter provides a basic auto-completion functionality. On `(Ctrl+.)` it list the most relevant suggestions in a pop-up window.
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ group: manual
|
|||
### Overview
|
||||
[Apache Ignite](https://ignite.apache.org/) In-Memory Data Fabric is a high-performance, integrated and distributed in-memory platform for computing and transacting on large-scale data sets in real-time, orders of magnitude faster than possible with traditional disk-based or flash technologies.
|
||||
|
||||

|
||||

|
||||
|
||||
You can use Zeppelin to retrieve distributed data from cache using Ignite SQL interpreter. Moreover, Ignite interpreter allows you to execute any Scala code in cases when SQL doesn't fit to your requirements. For example, you can populate data into your caches or execute distributed computations.
|
||||
|
||||
|
|
@ -68,12 +68,12 @@ At the "Interpreters" menu, you may edit Ignite interpreter or create new one. Z
|
|||
</tr>
|
||||
</table>
|
||||
|
||||

|
||||

|
||||
|
||||
### Interpreter Binding for Zeppelin Notebook
|
||||
After configuring Ignite interpreter, create your own notebook. Then you can bind interpreters like below image.
|
||||
|
||||

|
||||

|
||||
|
||||
For more interpreter binding information see [here](http://zeppelin.incubator.apache.org/docs/manual/interpreters.html).
|
||||
|
||||
|
|
@ -87,7 +87,7 @@ For example, you can select top 10 words in the words cache using the following
|
|||
select _val, count(_val) as cnt from String group by _val order by cnt desc limit 10
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
||||
As long as your Ignite version and Zeppelin Ignite version is same, you can also use scala code. Please check the Zeppelin Ignite version before you download your own Ignite.
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ As long as your Ignite version and Zeppelin Ignite version is same, you can also
|
|||
collectionAsScalaIterable(res).foreach(println _)
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
||||
Apache Ignite also provides a guide docs for Zeppelin ["Ignite with Apache Zeppelin"](https://apacheignite.readme.io/docs/data-analysis-with-apache-zeppelin)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ group: manual
|
|||
### Overview
|
||||
[Apache Lens](https://lens.apache.org/) provides an Unified Analytics interface. Lens aims to cut the Data Analytics silos by providing a single view of data across multiple tiered data stores and optimal execution environment for the analytical query. It seamlessly integrates Hadoop with traditional data warehouses to appear like one.
|
||||
|
||||

|
||||

|
||||
|
||||
### Installing and Running Lens
|
||||
In order to use Lens interpreters, you may install Apache Lens in some simple steps:
|
||||
|
|
@ -75,11 +75,11 @@ At the "Interpreters" menu, you can to edit Lens interpreter or create new one.
|
|||
</tr>
|
||||
</table>
|
||||
|
||||

|
||||

|
||||
|
||||
### Interpreter Bindging for Zeppelin Notebook
|
||||
After configuring Lens interpreter, create your own notebook, then you can bind interpreters like below image.
|
||||

|
||||

|
||||
|
||||
For more interpreter binding information see [here](http://zeppelin.incubator.apache.org/docs/manual/interpreters.html).
|
||||
|
||||
|
|
@ -159,14 +159,14 @@ As you can see in this video, they are using Lens Client Shell(./bin/lens-cli.sh
|
|||
```
|
||||
|
||||
|
||||

|
||||

|
||||
|
||||
These are just examples that provided in advance by Lens. If you want to explore whole tutorials of Lens, see the [tutorial video](https://cwiki.apache.org/confluence/display/LENS/2015/07/13/20+Minute+video+demo+of+Apache+Lens+through+examples).
|
||||
|
||||
### Lens UI Service
|
||||
Lens also provides web UI service. Once the server starts up, you can open the service on http://serverhost:19999/index.html and browse. You may also check the structure that you made and use query easily here.
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
|
||||
|
|
|
|||
22
docs/interpreter/markdown.md
Normal file
22
docs/interpreter/markdown.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
layout: page
|
||||
title: "Markdown Interpreter"
|
||||
description: "Markdown Interpreter"
|
||||
group: manual
|
||||
---
|
||||
{% include JB/setup %}
|
||||
|
||||
## Markdown Interpreter for Apache Zeppelin
|
||||
|
||||
### Overview
|
||||
[Markdown](http://daringfireball.net/projects/markdown/) is a plain text formatting syntax designed so that it can be converted to HTML.
|
||||
Zeppelin uses markdown4j, for more examples and extension support checkout [markdown4j](https://code.google.com/p/markdown4j/)
|
||||
In Zeppelin notebook you can use ``` %md ``` in the beginning of a paragraph to invoke the Markdown interpreter to generate static html from Markdown plain text.
|
||||
|
||||
In Zeppelin, Markdown interpreter is enabled by default.
|
||||
<img src="{{BASE_PATH}}/assets/themes/zeppelin/img/docs-img/markdown-interpreter-setting.png" width="600px" />
|
||||
|
||||
### Example
|
||||
The following example demonstrates the basic usage of Markdown in a Zeppelin notebook.
|
||||
|
||||
<img src="{{BASE_PATH}}/assets/themes/zeppelin/img/docs-img/markdown-example.png" width="800px" />
|
||||
|
|
@ -19,7 +19,7 @@ group: manual
|
|||
<tr>
|
||||
<td>%psql.sql</td>
|
||||
<td>PostgreSqlInterpreter</td>
|
||||
<td>Provides SQL environment for Postgresql, HAWQ and Greenplum</td>
|
||||
<td>Provides SQL environment for PostgreSQL, HAWQ and Greenplum</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
|
@ -28,22 +28,22 @@ group: manual
|
|||
|
||||
This interpreter seamlessly supports the following SQL data processing engines:
|
||||
|
||||
* [PostgreSQL](http://www.postgresql.org/) - OSS, Object-relational database management system (ORDBMS)
|
||||
* [Apache HAWQ](http://pivotal.io/big-data/pivotal-hawq) - Powerful [Open Source](https://wiki.apache.org/incubator/HAWQProposal) SQL-On-Hadoop engine.
|
||||
* [PostgreSQL](http://www.postgresql.org/) - OSS, Object-relational database management system (ORDBMS)
|
||||
* [Apache HAWQ](http://pivotal.io/big-data/pivotal-hawq) - Powerful [Open Source](https://wiki.apache.org/incubator/HAWQProposal) SQL-On-Hadoop engine.
|
||||
* [Greenplum](http://pivotal.io/big-data/pivotal-greenplum-database) - MPP database built on open source PostgreSQL.
|
||||
|
||||
|
||||
This [Video Tutorial](https://www.youtube.com/watch?v=wqXXQhJ5Uk8) illustrates some of the features provided by the `Postgresql Interpreter`.
|
||||
|
||||
### Create Interpreter
|
||||
### Create Interpreter
|
||||
|
||||
By default Zeppelin creates one `PSQL` instance. You can remove it or create new instances.
|
||||
By default Zeppelin creates one `PSQL` instance. You can remove it or create new instances.
|
||||
|
||||
Multiple PSQL instances can be created, each configured to the same or different backend databases. But over time a `Notebook` can have only one PSQL interpreter instance `bound`. That means you _can not_ connect to different databases in the same `Notebook`. This is a known Zeppelin limitation.
|
||||
Multiple PSQL instances can be created, each configured to the same or different backend databases. But over time a `Notebook` can have only one PSQL interpreter instance `bound`. That means you _cannot_ connect to different databases in the same `Notebook`. This is a known Zeppelin limitation.
|
||||
|
||||
To create new PSQL instance open the `Interprter` section and click the `+Create` button. Pick a `Name` of your choice and from the `Interpreter` drop-down select `psql`. Then follow the configuration instructions and `Save` the new instance.
|
||||
To create new PSQL instance open the `Interpreter` section and click the `+Create` button. Pick a `Name` of your choice and from the `Interpreter` drop-down select `psql`. Then follow the configuration instructions and `Save` the new instance.
|
||||
|
||||
> Note: The `Name` of the instance is used only to distinct the instances while binding them to the `Notebook`. The `Name` is irrelevant inside the `Notebook`. In the `Notebook` you must use `%psql.sql` tag.
|
||||
> Note: The `Name` of the instance is used only to distinct the instances while binding them to the `Notebook`. The `Name` is irrelevant inside the `Notebook`. In the `Notebook` you must use `%psql.sql` tag.
|
||||
|
||||
### Bind to Notebook
|
||||
In the `Notebook` click on the `settings` icon in the top right corner. The select/deselect the interpreters to be bound with the `Notebook`.
|
||||
|
|
@ -51,7 +51,7 @@ In the `Notebook` click on the `settings` icon in the top right corner. The sele
|
|||
### Configuration
|
||||
You can modify the configuration of the PSQL from the `Interpreter` section. The PSQL interpreter expenses the following properties:
|
||||
|
||||
|
||||
|
||||
<table class="table-configuration">
|
||||
<tr>
|
||||
<th>Property Name</th>
|
||||
|
|
@ -84,15 +84,15 @@ You can modify the configuration of the PSQL from the `Interpreter` section. Th
|
|||
<td>1000</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
### How to use
|
||||
```
|
||||
Tip: Use (CTRL + .) for SQL auto-completion.
|
||||
```
|
||||
#### DDL and SQL commands
|
||||
|
||||
Start the paragraphs with the full `%psql.sql` prefix tag! The short notation: `%psql` would still be able run the queries but the syntax highlighting and the auto-completions will be disabled.
|
||||
Start the paragraphs with the full `%psql.sql` prefix tag! The short notation: `%psql` would still be able run the queries but the syntax highlighting and the auto-completions will be disabled.
|
||||
|
||||
You can use the standard CREATE / DROP / INSERT commands to create or modify the data model:
|
||||
|
||||
|
|
@ -147,14 +147,14 @@ This will produce output like this:
|
|||
|
||||
#### Apply Zeppelin Dynamic Forms
|
||||
|
||||
You can leverage [Zepplein Dynamic Form](https://zeppelin.incubator.apache.org/docs/manual/dynamicform.html) inside your queries. You can use both the `text input` and `select form` parametrization features
|
||||
You can leverage [Zeppelin Dynamic Form](../manual/dynamicform.html) inside your queries. You can use both the `text input` and `select form` parametrization features
|
||||
|
||||
```sql
|
||||
%psql.sql
|
||||
SELECT ${group_by}, count(*) as count
|
||||
FROM retail_demo.order_lineitems_pxf
|
||||
GROUP BY ${group_by=product_id,product_id|product_name|customer_id|store_id}
|
||||
ORDER BY count ${order=DESC,DESC|ASC}
|
||||
SELECT ${group_by}, count(*) as count
|
||||
FROM retail_demo.order_lineitems_pxf
|
||||
GROUP BY ${group_by=product_id,product_id|product_name|customer_id|store_id}
|
||||
ORDER BY count ${order=DESC,DESC|ASC}
|
||||
LIMIT ${limit=10};
|
||||
```
|
||||
#### Example HAWQ PXF/HDFS Tables
|
||||
|
|
@ -172,9 +172,7 @@ And retrieve content
|
|||
|
||||
```sql
|
||||
%psql.sql
|
||||
seelect * from retail_demo.payment_methods_pxf
|
||||
select * from retail_demo.payment_methods_pxf
|
||||
```
|
||||
### Auto-completion
|
||||
The PSQL Interpreter provides a basic auto-completion functionality. On `(Ctrl+.)` it list the most relevant suggesntions in a pop-up window. In addition to the SQL keyword the interpter provides suggestions for the Schema, Table, Column names as well.
|
||||
|
||||
|
||||
### Auto-completion
|
||||
The PSQL Interpreter provides a basic auto-completion functionality. On `(Ctrl+.)` it list the most relevant suggestions in a pop-up window. In addition to the SQL keyword the interpreter provides suggestions for the Schema, Table, Column names as well.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ group: manual
|
|||
{% include JB/setup %}
|
||||
|
||||
|
||||
## Spark
|
||||
## Spark Interpreter
|
||||
|
||||
[Apache Spark](http://spark.apache.org) is supported in Zeppelin with
|
||||
Spark Interpreter group, which consisted of 4 interpreters.
|
||||
|
|
@ -41,10 +41,54 @@ Spark Interpreter group, which consisted of 4 interpreters.
|
|||
</table>
|
||||
|
||||
|
||||
<br /><br />
|
||||
|
||||
### Configuration
|
||||
<hr />
|
||||
|
||||
Without any configuration, Spark interpreter works out of box in local mode. But if you want to connect to your Spark cluster, you'll need following two simple steps.
|
||||
|
||||
|
||||
#### 1. export SPARK_HOME
|
||||
|
||||
In **conf/zeppelin-env.sh**, export SPARK_HOME environment variable with your Spark installation path.
|
||||
|
||||
for example
|
||||
|
||||
```bash
|
||||
export SPARK_HOME=/usr/lib/spark
|
||||
```
|
||||
|
||||
You can optionally export HADOOP\_CONF\_DIR and SPARK\_SUBMIT\_OPTIONS
|
||||
|
||||
```bash
|
||||
export HADOOP_CONF_DIR=/usr/lib/hadoop
|
||||
export SPARK_SUBMIT_OPTIONS="--packages com.databricks:spark-csv_2.10:1.2.0"
|
||||
```
|
||||
|
||||
|
||||
<br />
|
||||
#### 2. set master in Interpreter menu.
|
||||
|
||||
After start Zeppelin, go to **Interpreter** menu and edit **master** property in your Spark interpreter setting. The value may vary depending on your Spark cluster deployment type.
|
||||
|
||||
for example,
|
||||
|
||||
* **local[*]** in local mode
|
||||
* **spark://master:7077** in standalone cluster
|
||||
* **yarn-client** in Yarn client mode
|
||||
* **mesos://host:5050** in Mesos cluster
|
||||
|
||||
|
||||
|
||||
<br />
|
||||
That's it. Zeppelin will work with any version of Spark and any deployment type without rebuild Zeppelin in this way. (Zeppelin 0.5.5-incubating release works up to Spark 1.5.1)
|
||||
|
||||
Note that without exporting SPARK_HOME, it's running in local mode with included version of Spark. The included version may vary depending on the build profile.
|
||||
|
||||
<br /> <br />
|
||||
### SparkContext, SQLContext, ZeppelinContext
|
||||
<hr />
|
||||
|
||||
SparkContext, SQLContext, ZeppelinContext are automatically created and exposed as variable names 'sc', 'sqlContext' and 'z', respectively, both in scala and python environments.
|
||||
|
||||
|
|
@ -55,6 +99,7 @@ Note that scala / python environment shares the same SparkContext, SQLContext, Z
|
|||
<br />
|
||||
<br />
|
||||
### Dependency Management
|
||||
<hr />
|
||||
There are two ways to load external library in spark interpreter. First is using Zeppelin's %dep interpreter and second is loading Spark properties.
|
||||
|
||||
#### 1. Dynamic Dependency Loading via %dep interpreter
|
||||
|
|
@ -141,7 +186,6 @@ Note that adding jar to pyspark is only availabe via %dep interpreter at the mom
|
|||
<br/>
|
||||
Here are few examples:
|
||||
|
||||
##### 0.5.5 and later
|
||||
* SPARK\_SUBMIT\_OPTIONS in conf/zeppelin-env.sh
|
||||
|
||||
export SPARK_SUBMIT_OPTIONS="--packages com.databricks:spark-csv_2.10:1.2.0 --jars /path/mylib1.jar,/path/mylib2.jar --files /path/mylib1.py,/path/mylib2.zip,/path/mylib3.egg"
|
||||
|
|
@ -152,18 +196,10 @@ Here are few examples:
|
|||
spark.jars.packages com.databricks:spark-csv_2.10:1.2.0
|
||||
spark.files /path/mylib1.py,/path/mylib2.egg,/path/mylib3.zip
|
||||
|
||||
##### 0.5.0
|
||||
* ZEPPELIN\_JAVA\_OPTS in conf/zeppelin-env.sh
|
||||
|
||||
export ZEPPELIN_JAVA_OPTS="-Dspark.jars=/path/mylib1.jar,/path/mylib2.jar -Dspark.files=/path/myfile1.dat,/path/myfile2.dat"
|
||||
<br />
|
||||
|
||||
|
||||
<a name="zeppelincontext"> </a>
|
||||
<br />
|
||||
<br />
|
||||
### ZeppelinContext
|
||||
|
||||
<hr />
|
||||
|
||||
Zeppelin automatically injects ZeppelinContext as variable 'z' in your scala/python environment. ZeppelinContext provides some additional functions and utility.
|
||||
|
||||
|
|
@ -218,4 +254,4 @@ In sql environment, you can create form in simple template.
|
|||
select * from ${table=defaultTableName} where text like '%${search}%'
|
||||
```
|
||||
|
||||
To learn more about dynamic form, checkout [Dynamic Form](../dynamicform.html).
|
||||
To learn more about dynamic form, checkout [Dynamic Form](../manual/dynamicform.html).
|
||||
|
|
|
|||
|
|
@ -37,12 +37,12 @@ To create text input form, use _${formName}_ templates.
|
|||
|
||||
for example
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/form_input.png" />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/form_input.png" />
|
||||
|
||||
|
||||
Also you can provide default value, using _${formName=defaultValue}_.
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/form_input_default.png" />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/form_input_default.png" />
|
||||
|
||||
|
||||
<br />
|
||||
|
|
@ -52,11 +52,11 @@ To create select form, use _${formName=defaultValue,option1|option2...}_
|
|||
|
||||
for example
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/form_select.png" />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/form_select.png" />
|
||||
|
||||
Also you can separate option's display name and value, using _${formName=defaultValue,option1(DisplayName)|option2(DisplayName)...}_
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/form_select_displayname.png" />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/form_select_displayname.png" />
|
||||
|
||||
<br />
|
||||
### Creates Programmatically
|
||||
|
|
@ -68,38 +68,43 @@ Here're some examples.
|
|||
Text input form
|
||||
|
||||
You can do this in Scala
|
||||
|
||||
```scala
|
||||
%spark
|
||||
println("Hello "+z.input("name"))
|
||||
```
|
||||
|
||||
Or Python
|
||||
|
||||
```python
|
||||
%pyspark
|
||||
print("Hello "+z.input("name"))
|
||||
```
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/form_input_prog.png" />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/form_input_prog.png" />
|
||||
|
||||
Text input form with default value
|
||||
|
||||
Scala
|
||||
|
||||
```scala
|
||||
%spark
|
||||
println("Hello "+z.input("name", "sun"))
|
||||
```
|
||||
|
||||
Python
|
||||
|
||||
```python
|
||||
%pyspark
|
||||
print("Hello "+z.input("name", "sun"))
|
||||
```
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/form_input_default_prog.png" />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/form_input_default_prog.png" />
|
||||
|
||||
Select form
|
||||
|
||||
Scala
|
||||
|
||||
```scala
|
||||
%spark
|
||||
println("Hello "+z.select("day", Seq(("1","mon"),
|
||||
|
|
@ -112,6 +117,7 @@ println("Hello "+z.select("day", Seq(("1","mon"),
|
|||
```
|
||||
|
||||
Python
|
||||
|
||||
```python
|
||||
%pyspark
|
||||
print("Hello "+z.select("day", [("1","mon"),
|
||||
|
|
@ -123,4 +129,4 @@ print("Hello "+z.select("day", [("1","mon"),
|
|||
("7","sun")]))
|
||||
```
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/form_select_prog.png" />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/form_select_prog.png" />
|
||||
|
|
|
|||
|
|
@ -32,13 +32,13 @@ Zeppelin Interpreter is the plug-in which enable zeppelin user to use a specific
|
|||
|
||||
When you click on the ```+Create``` button in the interpreter page the interpreter drop-down list box will present all the available interpreters on your server.
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/interpreter_create.png">
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/interpreter_create.png">
|
||||
|
||||
### What is zeppelin interpreter setting?
|
||||
|
||||
Zeppelin interpreter setting is the configuration of a given interpreter on zeppelin server. For example, the properties requried for hive JDBC interpreter to connect to the Hive server.
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/interpreter_setting.png">
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/interpreter_setting.png">
|
||||
### What is zeppelin interpreter group?
|
||||
|
||||
Every Interpreter belongs to an InterpreterGroup. InterpreterGroup is a unit of start/stop interpreter.
|
||||
|
|
@ -48,7 +48,7 @@ SparkSQL and the dependency loader.
|
|||
Technically, Zeppelin interpreters from the same group are running in the same JVM.
|
||||
|
||||
Interpreters belong to a single group a registered together and all of their properties are listed in the interpreter setting.
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/interpreter_setting_spark.png">
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/interpreter_setting_spark.png">
|
||||
|
||||
### Programming langages for interpreter
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ The process for creating your homepage is very simple as shown below:
|
|||
|
||||
for example
|
||||
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/homepage_notebook_id.png" />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/homepage_notebook_id.png" />
|
||||
|
||||
Set the notebook id to the ```ZEPPELIN_NOTEBOOK_HOMESCREEN``` environment variable
|
||||
or ```zeppelin.notebook.homescreen``` property.
|
||||
|
|
@ -97,7 +97,7 @@ you need to do is use our %angular support.
|
|||
```
|
||||
|
||||
After running the notebook you will see output similar to this one:
|
||||
<img src="../../assets/themes/zeppelin/img/screenshots/homepage_notebook_list.png" />
|
||||
<img src="/assets/themes/zeppelin/img/screenshots/homepage_notebook_list.png" />
|
||||
|
||||
The main trick here relays in linking the ```<div>``` to the controller:
|
||||
|
||||
|
|
|
|||
|
|
@ -328,15 +328,6 @@
|
|||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
|
|
@ -284,6 +284,12 @@ public class PySparkInterpreter extends Interpreter implements ExecuteResultHand
|
|||
|
||||
@Override
|
||||
public InterpreterResult interpret(String st, InterpreterContext context) {
|
||||
SparkInterpreter sparkInterpreter = getSparkInterpreter();
|
||||
if (sparkInterpreter.getSparkVersion().isUnsupportedVersion()) {
|
||||
return new InterpreterResult(Code.ERROR, "Spark "
|
||||
+ sparkInterpreter.getSparkVersion().toString() + " is not supported");
|
||||
}
|
||||
|
||||
if (!pythonscriptRunning) {
|
||||
return new InterpreterResult(Code.ERROR, "python process not running"
|
||||
+ outputStream.toString());
|
||||
|
|
@ -314,7 +320,6 @@ public class PySparkInterpreter extends Interpreter implements ExecuteResultHand
|
|||
+ outputStream.toString());
|
||||
}
|
||||
|
||||
SparkInterpreter sparkInterpreter = getSparkInterpreter();
|
||||
if (!sparkInterpreter.getSparkVersion().isPysparkSupported()) {
|
||||
return new InterpreterResult(Code.ERROR, "pyspark "
|
||||
+ sparkInterpreter.getSparkContext().version() + " is not supported");
|
||||
|
|
|
|||
|
|
@ -605,6 +605,11 @@ public class SparkInterpreter extends Interpreter {
|
|||
*/
|
||||
@Override
|
||||
public InterpreterResult interpret(String line, InterpreterContext context) {
|
||||
if (sparkVersion.isUnsupportedVersion()) {
|
||||
return new InterpreterResult(Code.ERROR, "Spark " + sparkVersion.toString()
|
||||
+ " is not supported");
|
||||
}
|
||||
|
||||
z.setInterpreterContext(context);
|
||||
if (line == null || line.trim().length() == 0) {
|
||||
return new InterpreterResult(Code.SUCCESS);
|
||||
|
|
|
|||
|
|
@ -115,9 +115,14 @@ public class SparkSqlInterpreter extends Interpreter {
|
|||
@Override
|
||||
public InterpreterResult interpret(String st, InterpreterContext context) {
|
||||
SQLContext sqlc = null;
|
||||
SparkInterpreter sparkInterpreter = getSparkInterpreter();
|
||||
|
||||
if (sparkInterpreter.getSparkVersion().isUnsupportedVersion()) {
|
||||
return new InterpreterResult(Code.ERROR, "Spark "
|
||||
+ sparkInterpreter.getSparkVersion().toString() + " is not supported");
|
||||
}
|
||||
|
||||
sqlc = getSparkInterpreter().getSQLContext();
|
||||
|
||||
SparkContext sc = sqlc.sparkContext();
|
||||
if (concurrentSQL()) {
|
||||
sc.setLocalProperty("spark.scheduler.pool", "fair");
|
||||
|
|
|
|||
|
|
@ -16,29 +16,47 @@
|
|||
*/
|
||||
package org.apache.zeppelin.spark;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Provide reading comparing capability of spark version returned from SparkContext.version()
|
||||
*/
|
||||
public enum SparkVersion {
|
||||
SPARK_1_0_0,
|
||||
SPARK_1_0_1,
|
||||
SPARK_1_1_0,
|
||||
SPARK_1_1_1,
|
||||
SPARK_1_2_0,
|
||||
SPARK_1_2_1,
|
||||
SPARK_1_2_2,
|
||||
SPARK_1_3_0,
|
||||
SPARK_1_3_1,
|
||||
SPARK_1_4_0,
|
||||
SPARK_1_4_1,
|
||||
SPARK_1_5_0,
|
||||
SPARK_1_5_1,
|
||||
SPARK_1_5_2;
|
||||
public class SparkVersion {
|
||||
Logger logger = LoggerFactory.getLogger(SparkVersion.class);
|
||||
|
||||
public static final SparkVersion SPARK_1_0_0 = SparkVersion.fromVersionString("1.0.0");
|
||||
public static final SparkVersion SPARK_1_1_0 = SparkVersion.fromVersionString("1.1.0");
|
||||
public static final SparkVersion SPARK_1_2_0 = SparkVersion.fromVersionString("1.2.0");
|
||||
public static final SparkVersion SPARK_1_3_0 = SparkVersion.fromVersionString("1.3.0");
|
||||
public static final SparkVersion SPARK_1_4_0 = SparkVersion.fromVersionString("1.4.0");
|
||||
public static final SparkVersion SPARK_1_5_0 = SparkVersion.fromVersionString("1.5.0");
|
||||
public static final SparkVersion SPARK_1_6_0 = SparkVersion.fromVersionString("1.6.0");
|
||||
|
||||
public static final SparkVersion MIN_SUPPORTED_VERSION = SPARK_1_0_0;
|
||||
public static final SparkVersion UNSUPPORTED_FUTURE_VERSION = SPARK_1_6_0;
|
||||
|
||||
private int version;
|
||||
private String versionString;
|
||||
|
||||
SparkVersion() {
|
||||
version = Integer.parseInt(name().substring("SPARK_".length()).replaceAll("_", ""));
|
||||
SparkVersion(String versionString) {
|
||||
this.versionString = versionString;
|
||||
|
||||
try {
|
||||
int pos = versionString.indexOf('-');
|
||||
|
||||
String numberPart = versionString;
|
||||
if (pos > 0) {
|
||||
numberPart = versionString.substring(0, pos);
|
||||
}
|
||||
version = Integer.parseInt(numberPart.replaceAll("\\.", ""));
|
||||
} catch (Exception e) {
|
||||
logger.error("Can not recognize Spark version " + versionString +
|
||||
". Assume it's a future release", e);
|
||||
|
||||
// assume it is future release
|
||||
version = 999;
|
||||
}
|
||||
}
|
||||
|
||||
public int toNumber() {
|
||||
|
|
@ -46,17 +64,16 @@ public enum SparkVersion {
|
|||
}
|
||||
|
||||
public String toString() {
|
||||
return name().substring("SPARK_".length()).replaceAll("_", ".");
|
||||
return versionString;
|
||||
}
|
||||
|
||||
public boolean isUnsupportedVersion() {
|
||||
return olderThan(MIN_SUPPORTED_VERSION) || newerThanEquals(UNSUPPORTED_FUTURE_VERSION);
|
||||
}
|
||||
|
||||
|
||||
public static SparkVersion fromVersionString(String versionString) {
|
||||
for (SparkVersion v : values()) {
|
||||
// Check for the beginning of the version string to allow for "1.5.0-SNAPSHOT"
|
||||
if (versionString.startsWith(v.toString())) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
return new SparkVersion(versionString);
|
||||
}
|
||||
|
||||
public boolean isPysparkSupported() {
|
||||
|
|
@ -79,6 +96,10 @@ public enum SparkVersion {
|
|||
return this.olderThan(SPARK_1_3_0);
|
||||
}
|
||||
|
||||
public boolean equals(Object versionToCompare) {
|
||||
return version == ((SparkVersion) versionToCompare).version;
|
||||
}
|
||||
|
||||
public boolean newerThan(SparkVersion versionToCompare) {
|
||||
return version > versionToCompare.version;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,11 +22,24 @@ import org.junit.Test;
|
|||
|
||||
public class SparkVersionTest {
|
||||
|
||||
@Test
|
||||
public void testUnknownSparkVersion() {
|
||||
assertEquals(999, SparkVersion.fromVersionString("DEV-10.10").toNumber());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsupportedVersion() {
|
||||
assertTrue(SparkVersion.fromVersionString("9.9.9").isUnsupportedVersion());
|
||||
assertFalse(SparkVersion.fromVersionString("1.5.9").isUnsupportedVersion());
|
||||
assertTrue(SparkVersion.fromVersionString("0.9.0").isUnsupportedVersion());
|
||||
assertTrue(SparkVersion.UNSUPPORTED_FUTURE_VERSION.isUnsupportedVersion());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSparkVersion() {
|
||||
// test equals
|
||||
assertTrue(SparkVersion.SPARK_1_2_0 == SparkVersion.fromVersionString("1.2.0"));
|
||||
assertTrue(SparkVersion.SPARK_1_5_0 == SparkVersion.fromVersionString("1.5.0-SNAPSHOT"));
|
||||
assertEquals(SparkVersion.SPARK_1_2_0, SparkVersion.fromVersionString("1.2.0"));
|
||||
assertEquals(SparkVersion.SPARK_1_5_0, SparkVersion.fromVersionString("1.5.0-SNAPSHOT"));
|
||||
|
||||
// test newer than
|
||||
assertFalse(SparkVersion.SPARK_1_2_0.newerThan(SparkVersion.SPARK_1_2_0));
|
||||
|
|
|
|||
|
|
@ -121,7 +121,10 @@ public abstract class Interpreter {
|
|||
* Called when interpreter is no longer used.
|
||||
*/
|
||||
public void destroy() {
|
||||
getScheduler().stop();
|
||||
Scheduler scheduler = getScheduler();
|
||||
if (scheduler != null) {
|
||||
scheduler.stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -23,29 +23,21 @@ import java.util.*;
|
|||
|
||||
/**
|
||||
* Interpreter result template.
|
||||
*
|
||||
* @author Leemoonsoo
|
||||
*
|
||||
*/
|
||||
public class InterpreterResult implements Serializable {
|
||||
|
||||
/**
|
||||
* Type of result after code execution.
|
||||
*
|
||||
* @author Leemoonsoo
|
||||
*
|
||||
*/
|
||||
public static enum Code {
|
||||
SUCCESS,
|
||||
INCOMPLETE,
|
||||
ERROR
|
||||
ERROR,
|
||||
KEEP_PREVIOUS_RESULT
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of Data.
|
||||
*
|
||||
* @author Leemoonsoo
|
||||
*
|
||||
*/
|
||||
public static enum Type {
|
||||
TEXT,
|
||||
|
|
@ -99,7 +91,7 @@ public class InterpreterResult implements Serializable {
|
|||
int magicLength = lastType.getValue().name().length() + 1;
|
||||
// 1 for the last \n or space after magic
|
||||
int subStringPos = magicLength + lastType.getKey() + 1;
|
||||
return msg.substring(subStringPos);
|
||||
return msg.substring(subStringPos);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -116,7 +108,7 @@ public class InterpreterResult implements Serializable {
|
|||
return lastType.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private int getIndexOfType(String msg, Type t) {
|
||||
if (msg == null) {
|
||||
return 0;
|
||||
|
|
@ -124,7 +116,7 @@ public class InterpreterResult implements Serializable {
|
|||
String typeString = "%" + t.name().toLowerCase();
|
||||
return StringUtils.indexOf(msg, typeString );
|
||||
}
|
||||
|
||||
|
||||
private TreeMap<Integer, Type> buildIndexMap(String msg) {
|
||||
int lastIndexOftypes = 0;
|
||||
TreeMap<Integer, Type> typesLastIndexInMsg = new TreeMap<Integer, Type>();
|
||||
|
|
|
|||
|
|
@ -329,9 +329,13 @@ public class RemoteInterpreter extends Interpreter {
|
|||
public Scheduler getScheduler() {
|
||||
int maxConcurrency = 10;
|
||||
RemoteInterpreterProcess interpreterProcess = getInterpreterProcess();
|
||||
return SchedulerFactory.singleton().createOrGetRemoteScheduler(
|
||||
"remoteinterpreter_" + interpreterProcess.hashCode(), getInterpreterProcess(),
|
||||
maxConcurrency);
|
||||
if (interpreterProcess == null) {
|
||||
return null;
|
||||
} else {
|
||||
return SchedulerFactory.singleton().createOrGetRemoteScheduler(
|
||||
"remoteinterpreter_" + interpreterProcess.hashCode(), getInterpreterProcess(),
|
||||
maxConcurrency);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ import org.apache.zeppelin.display.AngularObjectRegistryListener;
|
|||
import org.apache.zeppelin.display.GUI;
|
||||
import org.apache.zeppelin.interpreter.ClassloaderInterpreter;
|
||||
import org.apache.zeppelin.interpreter.Interpreter;
|
||||
import org.apache.zeppelin.interpreter.Interpreter.FormType;
|
||||
import org.apache.zeppelin.interpreter.InterpreterContext;
|
||||
import org.apache.zeppelin.interpreter.InterpreterContextRunner;
|
||||
import org.apache.zeppelin.interpreter.InterpreterException;
|
||||
|
|
@ -62,7 +61,8 @@ import com.google.gson.Gson;
|
|||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
*
|
||||
* Entry point for Interpreter process.
|
||||
* Accepting thrift connections from ZeppelinServer.
|
||||
*/
|
||||
public class RemoteInterpreterServer
|
||||
extends Thread
|
||||
|
|
@ -233,6 +233,11 @@ public class RemoteInterpreterServer
|
|||
result = new InterpreterResult(Code.ERROR, Job.getStack(job.getException()));
|
||||
} else {
|
||||
result = (InterpreterResult) job.getReturn();
|
||||
|
||||
// in case of job abort in PENDING status, result can be null
|
||||
if (result == null) {
|
||||
result = new InterpreterResult(Code.KEEP_PREVIOUS_RESULT);
|
||||
}
|
||||
}
|
||||
return convert(result,
|
||||
context.getConfig(),
|
||||
|
|
@ -303,8 +308,16 @@ public class RemoteInterpreterServer
|
|||
@Override
|
||||
public void cancel(String className, RemoteInterpreterContext interpreterContext)
|
||||
throws TException {
|
||||
logger.info("cancel {} {}", className, interpreterContext.getParagraphId());
|
||||
Interpreter intp = getInterpreter(className);
|
||||
intp.cancel(convert(interpreterContext));
|
||||
String jobId = interpreterContext.getParagraphId();
|
||||
Job job = intp.getScheduler().removeFromWaitingQueue(jobId);
|
||||
|
||||
if (job != null) {
|
||||
job.setStatus(Status.ABORT);
|
||||
} else {
|
||||
intp.cancel(convert(interpreterContext));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
package org.apache.zeppelin.scheduler;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
|
@ -25,10 +26,7 @@ import java.util.concurrent.ExecutorService;
|
|||
import org.apache.zeppelin.scheduler.Job.Status;
|
||||
|
||||
/**
|
||||
* TODO(moon) : add description.
|
||||
*
|
||||
* @author Leemoonsoo
|
||||
*
|
||||
* FIFOScheduler runs submitted job sequentially
|
||||
*/
|
||||
public class FIFOScheduler implements Scheduler {
|
||||
List<Job> queue = new LinkedList<Job>();
|
||||
|
|
@ -83,20 +81,38 @@ public class FIFOScheduler implements Scheduler {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Job removeFromWaitingQueue(String jobId) {
|
||||
synchronized (queue) {
|
||||
Iterator<Job> it = queue.iterator();
|
||||
while (it.hasNext()) {
|
||||
Job job = it.next();
|
||||
if (job.getId().equals(jobId)) {
|
||||
it.remove();
|
||||
return job;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
synchronized (queue) {
|
||||
while (terminate == false) {
|
||||
if (runningJob != null || queue.isEmpty() == true) {
|
||||
try {
|
||||
queue.wait(500);
|
||||
} catch (InterruptedException e) {
|
||||
synchronized (queue) {
|
||||
if (runningJob != null || queue.isEmpty() == true) {
|
||||
try {
|
||||
queue.wait(500);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
runningJob = queue.remove(0);
|
||||
runningJob = queue.remove(0);
|
||||
}
|
||||
|
||||
final Scheduler scheduler = this;
|
||||
this.executor.execute(new Runnable() {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
package org.apache.zeppelin.scheduler;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
|
@ -25,10 +26,7 @@ import java.util.concurrent.ExecutorService;
|
|||
import org.apache.zeppelin.scheduler.Job.Status;
|
||||
|
||||
/**
|
||||
* TODO(moon) : add description.
|
||||
*
|
||||
* @author Leemoonsoo
|
||||
*
|
||||
* Parallel scheduler runs submitted job concurrently.
|
||||
*/
|
||||
public class ParallelScheduler implements Scheduler {
|
||||
List<Job> queue = new LinkedList<Job>();
|
||||
|
|
@ -63,6 +61,21 @@ public class ParallelScheduler implements Scheduler {
|
|||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Job removeFromWaitingQueue(String jobId) {
|
||||
synchronized (queue) {
|
||||
Iterator<Job> it = queue.iterator();
|
||||
while (it.hasNext()) {
|
||||
Job job = it.next();
|
||||
if (job.getId().equals(jobId)) {
|
||||
it.remove();
|
||||
return job;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Job> getJobsRunning() {
|
||||
List<Job> ret = new LinkedList<Job>();
|
||||
|
|
@ -87,9 +100,9 @@ public class ParallelScheduler implements Scheduler {
|
|||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
synchronized (queue) {
|
||||
while (terminate == false) {
|
||||
while (terminate == false) {
|
||||
Job job = null;
|
||||
synchronized (queue) {
|
||||
if (running.size() >= maxConcurrency || queue.isEmpty() == true) {
|
||||
try {
|
||||
queue.wait(500);
|
||||
|
|
@ -98,14 +111,12 @@ public class ParallelScheduler implements Scheduler {
|
|||
continue;
|
||||
}
|
||||
|
||||
Job job = queue.remove(0);
|
||||
job = queue.remove(0);
|
||||
running.add(job);
|
||||
Scheduler scheduler = this;
|
||||
|
||||
executor.execute(new JobRunner(scheduler, job));
|
||||
}
|
||||
Scheduler scheduler = this;
|
||||
|
||||
|
||||
executor.execute(new JobRunner(scheduler, job));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
package org.apache.zeppelin.scheduler;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
|
@ -32,7 +33,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* RemoteScheduler runs in ZeppelinServer and proxies Scheduler running on RemoteInterpreter
|
||||
*/
|
||||
public class RemoteScheduler implements Scheduler {
|
||||
Logger logger = LoggerFactory.getLogger(RemoteScheduler.class);
|
||||
|
|
@ -107,6 +108,21 @@ public class RemoteScheduler implements Scheduler {
|
|||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Job removeFromWaitingQueue(String jobId) {
|
||||
synchronized (queue) {
|
||||
Iterator<Job> it = queue.iterator();
|
||||
while (it.hasNext()) {
|
||||
Job job = it.next();
|
||||
if (job.getId().equals(jobId)) {
|
||||
it.remove();
|
||||
return job;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Job> getJobsRunning() {
|
||||
List<Job> ret = new LinkedList<Job>();
|
||||
|
|
|
|||
|
|
@ -20,10 +20,7 @@ package org.apache.zeppelin.scheduler;
|
|||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* TODO(moon) : add description.
|
||||
*
|
||||
* @author Leemoonsoo
|
||||
*
|
||||
* Interface for scheduler
|
||||
*/
|
||||
public interface Scheduler extends Runnable {
|
||||
public String getName();
|
||||
|
|
@ -34,5 +31,7 @@ public interface Scheduler extends Runnable {
|
|||
|
||||
public void submit(Job job);
|
||||
|
||||
public Job removeFromWaitingQueue(String jobId);
|
||||
|
||||
public void stop();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,30 @@ public class FIFOSchedulerTest extends TestCase {
|
|||
|
||||
assertTrue((500 > (Long)job1.getReturn()));
|
||||
assertEquals(null, job2.getReturn());
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void testRemoveFromWaitingQueue() throws InterruptedException{
|
||||
Scheduler s = schedulerSvc.createOrGetFIFOScheduler("test");
|
||||
assertEquals(0, s.getJobsRunning().size());
|
||||
assertEquals(0, s.getJobsWaiting().size());
|
||||
|
||||
Job job1 = new SleepingJob("job1", null, 500);
|
||||
Job job2 = new SleepingJob("job2", null, 500);
|
||||
|
||||
s.submit(job1);
|
||||
s.submit(job2);
|
||||
|
||||
Thread.sleep(200);
|
||||
|
||||
job1.abort();
|
||||
job2.abort();
|
||||
|
||||
Thread.sleep(200);
|
||||
|
||||
assertEquals(Status.ABORT, job1.getStatus());
|
||||
assertEquals(Status.ABORT, job2.getStatus());
|
||||
|
||||
assertTrue((500 > (Long)job1.getReturn()));
|
||||
assertEquals(null, job2.getReturn());
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,8 @@
|
|||
package org.apache.zeppelin.scheduler;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
|
|
@ -33,6 +35,7 @@ import org.apache.zeppelin.interpreter.InterpreterContextRunner;
|
|||
import org.apache.zeppelin.interpreter.InterpreterGroup;
|
||||
import org.apache.zeppelin.interpreter.remote.RemoteInterpreter;
|
||||
import org.apache.zeppelin.interpreter.remote.mock.MockInterpreterA;
|
||||
import org.apache.zeppelin.scheduler.Job.Status;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
|
@ -127,7 +130,7 @@ public class RemoteSchedulerTest {
|
|||
Thread.sleep(TICK_WAIT);
|
||||
cycles++;
|
||||
}
|
||||
|
||||
|
||||
assertTrue(job.isTerminated());
|
||||
assertEquals(0, scheduler.getJobsWaiting().size());
|
||||
assertEquals(0, scheduler.getJobsRunning().size());
|
||||
|
|
@ -136,4 +139,133 @@ public class RemoteSchedulerTest {
|
|||
schedulerSvc.removeScheduler("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbortOnPending() throws Exception {
|
||||
Properties p = new Properties();
|
||||
final InterpreterGroup intpGroup = new InterpreterGroup();
|
||||
Map<String, String> env = new HashMap<String, String>();
|
||||
env.put("ZEPPELIN_CLASSPATH", new File("./target/test-classes").getAbsolutePath());
|
||||
|
||||
final RemoteInterpreter intpA = new RemoteInterpreter(
|
||||
p,
|
||||
MockInterpreterA.class.getName(),
|
||||
new File("../bin/interpreter.sh").getAbsolutePath(),
|
||||
"fake",
|
||||
env,
|
||||
10 * 1000
|
||||
);
|
||||
|
||||
intpGroup.add(intpA);
|
||||
intpA.setInterpreterGroup(intpGroup);
|
||||
|
||||
intpA.open();
|
||||
|
||||
Scheduler scheduler = schedulerSvc.createOrGetRemoteScheduler("test",
|
||||
intpA.getInterpreterProcess(),
|
||||
10);
|
||||
|
||||
Job job1 = new Job("jobId1", "jobName1", null, 200) {
|
||||
InterpreterContext context = new InterpreterContext(
|
||||
"note",
|
||||
"jobId1",
|
||||
"title",
|
||||
"text",
|
||||
new HashMap<String, Object>(),
|
||||
new GUI(),
|
||||
new AngularObjectRegistry(intpGroup.getId(), null),
|
||||
new LinkedList<InterpreterContextRunner>());
|
||||
|
||||
@Override
|
||||
public int progress() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> info() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object jobRun() throws Throwable {
|
||||
intpA.interpret("1000", context);
|
||||
return "1000";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean jobAbort() {
|
||||
if (isRunning()) {
|
||||
intpA.cancel(context);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
Job job2 = new Job("jobId2", "jobName2", null, 200) {
|
||||
InterpreterContext context = new InterpreterContext(
|
||||
"note",
|
||||
"jobId2",
|
||||
"title",
|
||||
"text",
|
||||
new HashMap<String, Object>(),
|
||||
new GUI(),
|
||||
new AngularObjectRegistry(intpGroup.getId(), null),
|
||||
new LinkedList<InterpreterContextRunner>());
|
||||
|
||||
@Override
|
||||
public int progress() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> info() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object jobRun() throws Throwable {
|
||||
intpA.interpret("1000", context);
|
||||
return "1000";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean jobAbort() {
|
||||
if (isRunning()) {
|
||||
intpA.cancel(context);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
job2.setResult("result2");
|
||||
|
||||
scheduler.submit(job1);
|
||||
scheduler.submit(job2);
|
||||
|
||||
|
||||
int cycles = 0;
|
||||
while (!job1.isRunning() && cycles < MAX_WAIT_CYCLES) {
|
||||
Thread.sleep(TICK_WAIT);
|
||||
cycles++;
|
||||
}
|
||||
assertTrue(job1.isRunning());
|
||||
assertTrue(job2.getStatus() == Status.PENDING);
|
||||
|
||||
job2.abort();
|
||||
|
||||
cycles = 0;
|
||||
while (!job1.isTerminated() && cycles < MAX_WAIT_CYCLES) {
|
||||
Thread.sleep(TICK_WAIT);
|
||||
cycles++;
|
||||
}
|
||||
|
||||
assertNotNull(job1.getDateFinished());
|
||||
assertTrue(job1.isTerminated());
|
||||
assertNull(job2.getDateFinished());
|
||||
assertTrue(job2.isTerminated());
|
||||
assertEquals("result2", job2.getReturn());
|
||||
|
||||
intpA.close();
|
||||
schedulerSvc.removeScheduler("test");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ public class ZeppelinServer extends Application {
|
|||
jettyServer = setupJettyServer(conf);
|
||||
|
||||
// REST api
|
||||
final ServletContextHandler restApi = setupRestApiContextHandler();
|
||||
final ServletContextHandler restApi = setupRestApiContextHandler(conf);
|
||||
|
||||
// Notebook server
|
||||
final ServletContextHandler notebook = setupNotebookServer(conf);
|
||||
|
|
@ -170,7 +170,7 @@ public class ZeppelinServer extends Application {
|
|||
ServletContextHandler.SESSIONS);
|
||||
|
||||
cxfContext.setSessionHandler(new SessionHandler());
|
||||
cxfContext.setContextPath("/");
|
||||
cxfContext.setContextPath(conf.getServerContextPath());
|
||||
cxfContext.addServlet(servletHolder, "/ws/*");
|
||||
cxfContext.addFilter(new FilterHolder(CorsFilter.class), "/*",
|
||||
EnumSet.allOf(DispatcherType.class));
|
||||
|
|
@ -210,7 +210,7 @@ public class ZeppelinServer extends Application {
|
|||
return scf.getSslContext();
|
||||
}
|
||||
|
||||
private static ServletContextHandler setupRestApiContextHandler() {
|
||||
private static ServletContextHandler setupRestApiContextHandler(ZeppelinConfiguration conf) {
|
||||
final ServletHolder cxfServletHolder = new ServletHolder(new CXFNonSpringJaxrsServlet());
|
||||
cxfServletHolder.setInitParameter("javax.ws.rs.Application", ZeppelinServer.class.getName());
|
||||
cxfServletHolder.setName("rest");
|
||||
|
|
@ -218,8 +218,8 @@ public class ZeppelinServer extends Application {
|
|||
|
||||
final ServletContextHandler cxfContext = new ServletContextHandler();
|
||||
cxfContext.setSessionHandler(new SessionHandler());
|
||||
cxfContext.setContextPath("/api");
|
||||
cxfContext.addServlet(cxfServletHolder, "/*");
|
||||
cxfContext.setContextPath(conf.getServerContextPath());
|
||||
cxfContext.addServlet(cxfServletHolder, "/api/*");
|
||||
|
||||
cxfContext.addFilter(new FilterHolder(CorsFilter.class), "/*",
|
||||
EnumSet.allOf(DispatcherType.class));
|
||||
|
|
@ -230,12 +230,12 @@ public class ZeppelinServer extends Application {
|
|||
ZeppelinConfiguration conf) {
|
||||
|
||||
WebAppContext webApp = new WebAppContext();
|
||||
webApp.setContextPath(conf.getServerContextPath());
|
||||
File warPath = new File(conf.getString(ConfVars.ZEPPELIN_WAR));
|
||||
if (warPath.isDirectory()) {
|
||||
// Development mode, read from FS
|
||||
// webApp.setDescriptor(warPath+"/WEB-INF/web.xml");
|
||||
webApp.setResourceBase(warPath.getPath());
|
||||
webApp.setContextPath("/");
|
||||
webApp.setParentLoaderPriority(true);
|
||||
} else {
|
||||
// use packaged WAR
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ public class Message {
|
|||
CLONE_NOTE, // [c-s] clone new notebook
|
||||
// @param id id of note to clone
|
||||
// @param name name fpor the cloned note
|
||||
IMPORT_NOTE, // [c-s] import notebook
|
||||
// @param object notebook
|
||||
NOTE_UPDATE,
|
||||
|
||||
RUN_PARAGRAPH, // [c-s] run paragraph
|
||||
|
|
|
|||
|
|
@ -16,20 +16,17 @@
|
|||
*/
|
||||
package org.apache.zeppelin.socket;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.zeppelin.conf.ZeppelinConfiguration;
|
||||
import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars;
|
||||
import org.apache.zeppelin.display.AngularObject;
|
||||
import org.apache.zeppelin.display.AngularObjectRegistry;
|
||||
import org.apache.zeppelin.display.AngularObjectRegistryListener;
|
||||
import org.apache.zeppelin.display.Input;
|
||||
import org.apache.zeppelin.interpreter.InterpreterResult;
|
||||
import org.apache.zeppelin.interpreter.InterpreterSetting;
|
||||
import org.apache.zeppelin.notebook.JobListenerFactory;
|
||||
|
|
@ -119,6 +116,9 @@ public class NotebookServer extends WebSocketServlet implements
|
|||
case CLONE_NOTE:
|
||||
cloneNote(conn, notebook, messagereceived);
|
||||
break;
|
||||
case IMPORT_NOTE:
|
||||
importNote(conn, notebook, messagereceived);
|
||||
break;
|
||||
case COMMIT_PARAGRAPH:
|
||||
updateParagraph(conn, notebook, messagereceived);
|
||||
break;
|
||||
|
|
@ -171,7 +171,7 @@ public class NotebookServer extends WebSocketServlet implements
|
|||
}
|
||||
}
|
||||
|
||||
private Message deserializeMessage(String msg) {
|
||||
protected Message deserializeMessage(String msg) {
|
||||
return gson.fromJson(msg, Message.class);
|
||||
}
|
||||
|
||||
|
|
@ -467,6 +467,61 @@ public class NotebookServer extends WebSocketServlet implements
|
|||
broadcastNoteList();
|
||||
}
|
||||
|
||||
protected Note importNote(NotebookSocket conn, Notebook notebook, Message fromMessage)
|
||||
throws IOException {
|
||||
|
||||
Note note = notebook.createNote();
|
||||
if (fromMessage != null) {
|
||||
String noteName = (String) ((Map) fromMessage.get("notebook")).get("name");
|
||||
if (noteName == null || noteName.isEmpty()) {
|
||||
noteName = "Note " + note.getId();
|
||||
}
|
||||
note.setName(noteName);
|
||||
ArrayList<Map> paragraphs = ((Map<String, ArrayList>) fromMessage.get("notebook"))
|
||||
.get("paragraphs");
|
||||
if (paragraphs.size() > 0) {
|
||||
for (Map paragraph : paragraphs) {
|
||||
try {
|
||||
Paragraph p = note.addParagraph();
|
||||
String text = (String) paragraph.get("text");
|
||||
p.setText(text);
|
||||
p.setTitle((String) paragraph.get("title"));
|
||||
Map<String, Object> params = (Map<String, Object>) ((Map) paragraph
|
||||
.get("settings")).get("params");
|
||||
Map<String, Input> forms = (Map<String, Input>) ((Map) paragraph
|
||||
.get("settings")).get("forms");
|
||||
if (params != null) {
|
||||
p.settings.setParams(params);
|
||||
}
|
||||
if (forms != null) {
|
||||
p.settings.setForms(forms);
|
||||
}
|
||||
Map<String, Object> result = (Map) paragraph.get("result");
|
||||
if (result != null) {
|
||||
InterpreterResult.Code code = InterpreterResult.Code
|
||||
.valueOf((String) result.get("code"));
|
||||
InterpreterResult.Type type = InterpreterResult.Type
|
||||
.valueOf((String) result.get("type"));
|
||||
String msg = (String) result.get("msg");
|
||||
p.setReturn(new InterpreterResult(code, type, msg), null);
|
||||
}
|
||||
|
||||
Map<String, Object> config = (Map<String, Object>) paragraph
|
||||
.get("config");
|
||||
p.setConfig(config);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Exception while setting parameter in paragraph", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
note.persist();
|
||||
broadcastNote(note);
|
||||
broadcastNoteList();
|
||||
return note;
|
||||
}
|
||||
|
||||
private void removeParagraph(NotebookSocket conn, Notebook notebook,
|
||||
Message fromMessage) throws IOException {
|
||||
final String paragraphId = (String) fromMessage.get("id");
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ public class ZeppelinIT {
|
|||
notebookTitles.add(el.getText());
|
||||
}
|
||||
|
||||
WebElement createNoteLink = driver.findElement(By.xpath("//div[contains(@class, \"col-md-4\")]/div/h5/a"));
|
||||
WebElement createNoteLink = driver.findElement(By.xpath("//div[contains(@class, \"col-md-4\")]/div/h5/a[contains(.,'Create new note')]"));
|
||||
createNoteLink.click();
|
||||
|
||||
WebDriverWait block = new WebDriverWait(driver, 10);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
package org.apache.zeppelin.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
|
@ -155,8 +156,11 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi {
|
|||
Note note = ZeppelinServer.notebook.createNote();
|
||||
note.addParagraph();
|
||||
Paragraph p = note.getLastParagraph();
|
||||
Map config = p.getConfig();
|
||||
config.put("enabled", true);
|
||||
|
||||
// run markdown paragraph
|
||||
p.setConfig(config);
|
||||
p.setText("%md markdown");
|
||||
note.run(p.getId());
|
||||
while (p.getStatus() != Status.FINISHED) {
|
||||
|
|
@ -175,6 +179,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi {
|
|||
|
||||
// run markdown paragraph, again
|
||||
p = note.addParagraph();
|
||||
p.setConfig(config);
|
||||
p.setText("%md markdown restarted");
|
||||
note.run(p.getId());
|
||||
while (p.getStatus() != Status.FINISHED) {
|
||||
|
|
@ -262,6 +267,9 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi {
|
|||
assertNotNull("can't create new note", note);
|
||||
note.setName("source note for clone");
|
||||
Paragraph paragraph = note.addParagraph();
|
||||
Map config = paragraph.getConfig();
|
||||
config.put("enabled", true);
|
||||
paragraph.setConfig(config);
|
||||
paragraph.setText("%md This is my new paragraph in my new note");
|
||||
note.persist();
|
||||
String sourceNoteID = note.getId();
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@ import static org.junit.Assert.assertEquals;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.zeppelin.interpreter.InterpreterSetting;
|
||||
|
|
@ -52,7 +54,9 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
|
|||
}
|
||||
|
||||
private void waitForFinish(Paragraph p) {
|
||||
while (p.getStatus() != Status.FINISHED) {
|
||||
while (p.getStatus() != Status.FINISHED
|
||||
&& p.getStatus() != Status.ERROR
|
||||
&& p.getStatus() != Status.ABORT) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
|
|
@ -68,9 +72,13 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
|
|||
|
||||
// run markdown paragraph, again
|
||||
Paragraph p = note.addParagraph();
|
||||
Map config = p.getConfig();
|
||||
config.put("enabled", true);
|
||||
p.setConfig(config);
|
||||
p.setText("%spark print(sc.parallelize(1 to 10).reduce(_ + _))");
|
||||
note.run(p.getId());
|
||||
waitForFinish(p);
|
||||
assertEquals(Status.FINISHED, p.getStatus());
|
||||
assertEquals("55", p.getResult().message());
|
||||
ZeppelinServer.notebook.removeNote(note.id());
|
||||
}
|
||||
|
|
@ -84,9 +92,13 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
|
|||
if (isPyspark() && sparkVersion >= 12) { // pyspark supported from 1.2.1
|
||||
// run markdown paragraph, again
|
||||
Paragraph p = note.addParagraph();
|
||||
Map config = p.getConfig();
|
||||
config.put("enabled", true);
|
||||
p.setConfig(config);
|
||||
p.setText("%pyspark print(sc.parallelize(range(1, 11)).reduce(lambda a, b: a + b))");
|
||||
note.run(p.getId());
|
||||
waitForFinish(p);
|
||||
assertEquals(Status.FINISHED, p.getStatus());
|
||||
assertEquals("55\n", p.getResult().message());
|
||||
}
|
||||
ZeppelinServer.notebook.removeNote(note.id());
|
||||
|
|
@ -102,10 +114,14 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
|
|||
if (isPyspark() && sparkVersion >= 14) { // auto_convert enabled from spark 1.4
|
||||
// run markdown paragraph, again
|
||||
Paragraph p = note.addParagraph();
|
||||
Map config = p.getConfig();
|
||||
config.put("enabled", true);
|
||||
p.setConfig(config);
|
||||
p.setText("%pyspark\nfrom pyspark.sql.functions import *\n"
|
||||
+ "print(sqlContext.range(0, 10).withColumn('uniform', rand(seed=10) * 3.14).count())");
|
||||
note.run(p.getId());
|
||||
waitForFinish(p);
|
||||
assertEquals(Status.FINISHED, p.getStatus());
|
||||
assertEquals("10\n", p.getResult().message());
|
||||
}
|
||||
ZeppelinServer.notebook.removeNote(note.id());
|
||||
|
|
@ -116,17 +132,28 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
|
|||
// create new note
|
||||
Note note = ZeppelinServer.notebook.createNote();
|
||||
Paragraph p0 = note.addParagraph();
|
||||
Map config0 = p0.getConfig();
|
||||
config0.put("enabled", true);
|
||||
p0.setConfig(config0);
|
||||
p0.setText("%spark z.run(1)");
|
||||
Paragraph p1 = note.addParagraph();
|
||||
Map config1 = p1.getConfig();
|
||||
config1.put("enabled", true);
|
||||
p1.setConfig(config1);
|
||||
p1.setText("%spark val a=10");
|
||||
Paragraph p2 = note.addParagraph();
|
||||
Map config2 = p2.getConfig();
|
||||
config2.put("enabled", true);
|
||||
p2.setConfig(config2);
|
||||
p2.setText("%spark print(a)");
|
||||
|
||||
note.run(p0.getId());
|
||||
waitForFinish(p0);
|
||||
assertEquals(Status.FINISHED, p0.getStatus());
|
||||
|
||||
note.run(p2.getId());
|
||||
waitForFinish(p2);
|
||||
assertEquals(Status.FINISHED, p2.getStatus());
|
||||
assertEquals("10", p2.getResult().message());
|
||||
|
||||
ZeppelinServer.notebook.removeNote(note.id());
|
||||
|
|
@ -151,9 +178,13 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
|
|||
|
||||
// load dep
|
||||
Paragraph p0 = note.addParagraph();
|
||||
Map config = p0.getConfig();
|
||||
config.put("enabled", true);
|
||||
p0.setConfig(config);
|
||||
p0.setText("%dep z.load(\"com.databricks:spark-csv_2.11:1.2.0\")");
|
||||
note.run(p0.getId());
|
||||
waitForFinish(p0);
|
||||
assertEquals(Status.FINISHED, p0.getStatus());
|
||||
|
||||
// write test csv file
|
||||
File tmpFile = File.createTempFile("test", "csv");
|
||||
|
|
@ -161,6 +192,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
|
|||
|
||||
// load data using libraries from dep loader
|
||||
Paragraph p1 = note.addParagraph();
|
||||
p1.setConfig(config);
|
||||
p1.setText("%pyspark\n" +
|
||||
"from pyspark.sql import SQLContext\n" +
|
||||
"print(sqlContext.read.format('com.databricks.spark.csv')" +
|
||||
|
|
@ -168,6 +200,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
|
|||
note.run(p1.getId());
|
||||
|
||||
waitForFinish(p1);
|
||||
assertEquals(Status.FINISHED, p1.getStatus());
|
||||
assertEquals("2\n", p1.getResult().message());
|
||||
}
|
||||
}
|
||||
|
|
@ -178,9 +211,13 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
|
|||
*/
|
||||
private int getSparkVersionNumber(Note note) {
|
||||
Paragraph p = note.addParagraph();
|
||||
Map config = p.getConfig();
|
||||
config.put("enabled", true);
|
||||
p.setConfig(config);
|
||||
p.setText("%spark print(sc.version)");
|
||||
note.run(p.getId());
|
||||
waitForFinish(p);
|
||||
assertEquals(Status.FINISHED, p.getStatus());
|
||||
String sparkVersion = p.getResult().message();
|
||||
System.out.println("Spark version detected " + sparkVersion);
|
||||
String[] split = sparkVersion.split("\\.");
|
||||
|
|
|
|||
|
|
@ -136,6 +136,27 @@ public class NotebookServerTest extends AbstractTestRestApi {
|
|||
notebook.removeNote(note1.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImportNotebook() throws IOException {
|
||||
String msg = "{\"op\":\"IMPORT_NOTE\",\"data\":" +
|
||||
"{\"notebook\":{\"paragraphs\": [{\"text\": \"Test " +
|
||||
"paragraphs import\",\"config\":{},\"settings\":{}}]," +
|
||||
"\"name\": \"Test Zeppelin notebook import\",\"config\": " +
|
||||
"{}}}}";
|
||||
Message messageReceived = notebookServer.deserializeMessage(msg);
|
||||
Note note = null;
|
||||
try {
|
||||
note = notebookServer.importNote(null, notebook, messageReceived);
|
||||
} catch (NullPointerException e) {
|
||||
//broadcastNoteList(); failed nothing to worry.
|
||||
}
|
||||
|
||||
assertNotEquals(null, notebook.getNote(note.getId()));
|
||||
assertEquals("Test Zeppelin notebook import", notebook.getNote(note.getId()).getName());
|
||||
assertEquals("Test paragraphs import", notebook.getNote(note.getId()).getParagraphs().get(0).getText());
|
||||
notebook.removeNote(note.getId());
|
||||
}
|
||||
|
||||
private NotebookSocket createWebSocket() {
|
||||
NotebookSocket sock = mock(NotebookSocket.class);
|
||||
when(sock.getRequest()).thenReturn(createHttpServletRequest());
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@
|
|||
"confirm": false,
|
||||
"alert": false,
|
||||
"nv": false,
|
||||
"$": false,
|
||||
"ace": false,
|
||||
"d3": false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,30 +130,37 @@ a.navbar-brand:hover {
|
|||
.navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
|
||||
color: #D3D3D3;
|
||||
}
|
||||
|
||||
.navbar-nav .open .dropdown-menu > .scrollbar-container > li > a {
|
||||
padding: 5px 15px 5px 25px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > li > a {
|
||||
color: #D3D3D3;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > li > a:hover,
|
||||
.navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > li > a:focus {
|
||||
color: #fff;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > .active > a,
|
||||
.navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > .active > a:hover,
|
||||
.navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > .active > a:focus {
|
||||
color: #fff;
|
||||
background-color: #080808;
|
||||
}
|
||||
.server-status{
|
||||
|
||||
.server-status {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-nav .open .dropdown-menu .divider {
|
||||
background-color: #3071A9;
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form {
|
||||
border-color: #3071A9;
|
||||
}
|
||||
|
|
@ -210,7 +217,7 @@ a.navbar-brand:hover {
|
|||
.box-heading {
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
font-weight:300;
|
||||
font-weight: 300;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
|
|
@ -310,3 +317,374 @@ This part should be removed when new version of bootstrap handles this issue.
|
|||
.btn-group > .popover + .btn {
|
||||
margin-left: -1px;
|
||||
}
|
||||
|
||||
.display-inline {
|
||||
display: inline;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#noteImportModal .modal-body {
|
||||
min-height: 420px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#noteImportModal .modal-footer {
|
||||
min-height: 65px;
|
||||
}
|
||||
|
||||
#noteImportModal .display-inline a {
|
||||
background-color: #fff;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
float: left;
|
||||
font-size: 98px;
|
||||
height: 240px;
|
||||
margin: 0 10px 16px;
|
||||
padding-top: 60px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
width: 264px;
|
||||
}
|
||||
|
||||
#noteImportModal .display-inline a:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
#noteImportModal .display-inline a p {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* ------------------------------------------- */
|
||||
/* Slide Top
|
||||
/* ------------------------------------------- */
|
||||
.slide-top {
|
||||
-webkit-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-moz-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-ms-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-o-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
/* easeOutQuad */
|
||||
-webkit-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-moz-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-ms-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-o-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
/* easeOutQuad */
|
||||
}
|
||||
|
||||
.slide-top.ng-enter {
|
||||
transform: translateY(60px);
|
||||
-ms-transform: translateY(60px);
|
||||
-webkit-transform: translateY(60px);
|
||||
transition-duration: 250ms;
|
||||
-webkit-transition-duration: 250ms;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slide-top.ng-enter-active {
|
||||
transform: translateY(0);
|
||||
-ms-transform: translateY(0);
|
||||
-webkit-transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.slide-top.ng-leave {
|
||||
transform: translateY(0);
|
||||
-ms-transform: translateY(0);
|
||||
-webkit-transform: translateY(0);
|
||||
transition-duration: 250ms;
|
||||
-webkit-transition-duration: 250ms;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.slide-top.ng-leave-active {
|
||||
transform: translateY(60px);
|
||||
-ms-transform: translateY(60px);
|
||||
-webkit-transform: translateY(60px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slide-top.ng-hide-add {
|
||||
transform: translateY(0);
|
||||
-ms-transform: translateY(0);
|
||||
-webkit-transform: translateY(0);
|
||||
transition-duration: 250ms;
|
||||
-webkit-transition-duration: 250ms;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.slide-top.ng-hide-add.ng-hide-add-active {
|
||||
transform: translateY(60px);
|
||||
-ms-transform: translateY(60px);
|
||||
-webkit-transform: translateY(60px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slide-top.ng-hide-remove {
|
||||
transform: translateY(60px);
|
||||
-ms-transform: translateY(60px);
|
||||
-webkit-transform: translateY(60px);
|
||||
transition-duration: 250ms;
|
||||
-webkit-transition-duration: 250ms;
|
||||
display: block !important;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slide-top.ng-hide-remove.ng-hide-remove-active {
|
||||
transform: translateY(0);
|
||||
-ms-transform: translateY(0);
|
||||
-webkit-transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------- */
|
||||
/* Slide Right
|
||||
/* ------------------------------------------- */
|
||||
.slide-right {
|
||||
-webkit-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-moz-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-ms-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-o-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
/* easeOutQuad */
|
||||
-webkit-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-moz-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-ms-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-o-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
/* easeOutQuad */
|
||||
}
|
||||
|
||||
.slide-right.ng-enter {
|
||||
transform: translateX(60px);
|
||||
-ms-transform: translateX(60px);
|
||||
-webkit-transform: translateX(60px);
|
||||
transition-duration: 250ms;
|
||||
-webkit-transition-duration: 250ms;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slide-right.ng-enter-active {
|
||||
transform: translateX(0);
|
||||
-ms-transform: translateX(0);
|
||||
-webkit-transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.slide-right.ng-leave {
|
||||
transform: translateX(0);
|
||||
-ms-transform: translateX(0);
|
||||
-webkit-transform: translateX(0);
|
||||
transition-duration: 250ms;
|
||||
-webkit-transition-duration: 250ms;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.slide-right.ng-leave-active {
|
||||
transform: translateX(60px);
|
||||
-ms-transform: translateX(60px);
|
||||
-webkit-transform: translateX(60px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slide-right.ng-hide-add {
|
||||
transform: translateX(0);
|
||||
-ms-transform: translateX(0);
|
||||
-webkit-transform: translateX(0);
|
||||
transition-duration: 250ms;
|
||||
-webkit-transition-duration: 250ms;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.slide-right.ng-hide-add.ng-hide-add-active {
|
||||
transform: translateX(60px);
|
||||
-ms-transform: translateX(60px);
|
||||
-webkit-transform: translateX(60px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slide-right.ng-hide-remove {
|
||||
transform: translateX(60px);
|
||||
-ms-transform: translateX(60px);
|
||||
-webkit-transform: translateX(60px);
|
||||
transition-duration: 250ms;
|
||||
-webkit-transition-duration: 250ms;
|
||||
display: block !important;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slide-right.ng-hide-remove.ng-hide-remove-active {
|
||||
transform: translateX(0);
|
||||
-ms-transform: translateX(0);
|
||||
-webkit-transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------- */
|
||||
/* Slide Left
|
||||
/* ------------------------------------------- */
|
||||
.slide-left {
|
||||
-webkit-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-moz-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-ms-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-o-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
/* easeOutQuad */
|
||||
-webkit-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-moz-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-ms-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-o-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
/* easeOutQuad */
|
||||
}
|
||||
|
||||
.slide-left.ng-enter {
|
||||
transform: translateX(-60px);
|
||||
-ms-transform: translateX(-60px);
|
||||
-webkit-transform: translateX(-60px);
|
||||
transition-duration: 250ms;
|
||||
-webkit-transition-duration: 250ms;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slide-left.ng-enter-active {
|
||||
transform: translateX(0);
|
||||
-ms-transform: translateX(0);
|
||||
-webkit-transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.slide-left.ng-leave {
|
||||
transform: translateX(0);
|
||||
-ms-transform: translateX(0);
|
||||
-webkit-transform: translateX(0);
|
||||
transition-duration: 250ms;
|
||||
-webkit-transition-duration: 250ms;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.slide-left.ng-leave-active {
|
||||
transform: translateX(-60px);
|
||||
-ms-transform: translateX(-60px);
|
||||
-webkit-transform: translateX(-60px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slide-left.ng-hide-add {
|
||||
transform: translateX(0);
|
||||
-ms-transform: translateX(0);
|
||||
-webkit-transform: translateX(0);
|
||||
transition-duration: 250ms;
|
||||
-webkit-transition-duration: 250ms;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.slide-left.ng-hide-add.ng-hide-add-active {
|
||||
transform: translateX(-60px);
|
||||
-ms-transform: translateX(-60px);
|
||||
-webkit-transform: translateX(-60px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slide-left.ng-hide-remove {
|
||||
transform: translateX(-60px);
|
||||
-ms-transform: translateX(-60px);
|
||||
-webkit-transform: translateX(-60px);
|
||||
transition-duration: 250ms;
|
||||
-webkit-transition-duration: 250ms;
|
||||
display: block !important;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slide-left.ng-hide-remove.ng-hide-remove-active {
|
||||
transform: translateX(0);
|
||||
-ms-transform: translateX(0);
|
||||
-webkit-transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------- */
|
||||
/* Slide Down
|
||||
/* ------------------------------------------- */
|
||||
.slide-down {
|
||||
-webkit-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-moz-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-ms-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-o-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
/* easeOutQuad */
|
||||
-webkit-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-moz-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-ms-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
-o-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
/* easeOutQuad */
|
||||
}
|
||||
|
||||
.slide-down.ng-enter {
|
||||
transform: translateY(-60px);
|
||||
-ms-transform: translateY(-60px);
|
||||
-webkit-transform: translateY(-60px);
|
||||
transition-duration: 250ms;
|
||||
-webkit-transition-duration: 250ms;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slide-down.ng-enter-active {
|
||||
transform: translateY(0);
|
||||
-ms-transform: translateY(0);
|
||||
-webkit-transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.slide-down.ng-leave {
|
||||
transform: translateY(0);
|
||||
-ms-transform: translateY(0);
|
||||
-webkit-transform: translateY(0);
|
||||
transition-duration: 250ms;
|
||||
-webkit-transition-duration: 250ms;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.slide-down.ng-leave-active {
|
||||
transform: translateY(-60px);
|
||||
-ms-transform: translateY(-60px);
|
||||
-webkit-transform: translateY(-60px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slide-down.ng-hide-add {
|
||||
transform: translateY(0);
|
||||
-ms-transform: translateY(0);
|
||||
-webkit-transform: translateY(0);
|
||||
transition-duration: 250ms;
|
||||
-webkit-transition-duration: 250ms;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.slide-down.ng-hide-add.ng-hide-add-active {
|
||||
transform: translateY(-60px);
|
||||
-ms-transform: translateY(-60px);
|
||||
-webkit-transform: translateY(-60px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slide-down.ng-hide-remove {
|
||||
transform: translateY(-60px);
|
||||
-ms-transform: translateY(-60px);
|
||||
-webkit-transform: translateY(-60px);
|
||||
transition-duration: 250ms;
|
||||
-webkit-transition-duration: 250ms;
|
||||
display: block !important;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slide-down.ng-hide-remove.ng-hide-remove-active {
|
||||
transform: translateY(0);
|
||||
-ms-transform: translateY(0);
|
||||
-webkit-transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ limitations under the License.
|
|||
<h4>Notebook</h4>
|
||||
|
||||
<div>
|
||||
<h5><a href="" data-toggle="modal" data-target="#noteImportModal" style="text-decoration: none;">
|
||||
<i style="font-size: 15px;" class="fa fa-upload"></i> Import note</a></h5>
|
||||
<h5><a href="" data-toggle="modal" data-target="#noteNameModal" style="text-decoration: none;">
|
||||
<i style="font-size: 15px;" class="icon-notebook"></i> Create new note</a></h5>
|
||||
<ul style="list-style-type: none;">
|
||||
|
|
|
|||
|
|
@ -70,10 +70,10 @@ limitations under the License.
|
|||
<span class="btn btn-primary" ng-click="addNewInterpreterSetting()">
|
||||
Save
|
||||
</span>
|
||||
<span class="btn btn-default" ng-click="showAddNewSetting=false">
|
||||
<span class="btn btn-default" ng-click="cancelInterpreterSetting()">
|
||||
Cancel
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -163,6 +163,10 @@ angular.module('zeppelinWebApp').controller('InterpreterCtrl', function($scope,
|
|||
});
|
||||
};
|
||||
|
||||
$scope.cancelInterpreterSetting = function() {
|
||||
$scope.showAddNewSetting = false;
|
||||
};
|
||||
|
||||
$scope.resetNewInterpreterSetting = function() {
|
||||
$scope.newInterpreterSetting = {
|
||||
name : undefined,
|
||||
|
|
|
|||
|
|
@ -280,10 +280,13 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newIndex<0 || newIndex>=$scope.note.paragraphs.length) {
|
||||
return;
|
||||
}
|
||||
// save dirtyText of moving paragraphs.
|
||||
var prevParagraphId = $scope.note.paragraphs[newIndex].id;
|
||||
angular.element('#' + paragraphId + '_paragraphColumn_main').scope().saveParagraph();
|
||||
angular.element('#' + prevParagraphId + '_paragraphColumn_main').scope().saveParagraph();
|
||||
websocketMsgSrv.moveParagraph(paragraphId, newIndex);
|
||||
});
|
||||
|
||||
|
|
@ -315,6 +318,10 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro
|
|||
if (newIndex<0 || newIndex>=$scope.note.paragraphs.length) {
|
||||
return;
|
||||
}
|
||||
// save dirtyText of moving paragraphs.
|
||||
var nextParagraphId = $scope.note.paragraphs[newIndex].id;
|
||||
angular.element('#' + paragraphId + '_paragraphColumn_main').scope().saveParagraph();
|
||||
angular.element('#' + nextParagraphId + '_paragraphColumn_main').scope().saveParagraph();
|
||||
websocketMsgSrv.moveParagraph(paragraphId, newIndex);
|
||||
});
|
||||
|
||||
|
|
@ -412,7 +419,7 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro
|
|||
$http.get(baseUrlSrv.getRestApiBase()+ '/notebook/interpreter/bind/' +$scope.note.id).
|
||||
success(function(data, status, headers, config) {
|
||||
$scope.interpreterBindings = data.body;
|
||||
$scope.interpreterBindingsOrig = jQuery.extend(true, [], $scope.interpreterBindings); // to check dirty
|
||||
$scope.interpreterBindingsOrig = angular.copy($scope.interpreterBindings); // to check dirty
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,12 +54,14 @@ angular.module('zeppelinWebApp')
|
|||
|
||||
$scope.renderHtml = function() {
|
||||
var retryRenderer = function() {
|
||||
if ($('#p'+$scope.paragraph.id+'_html').length) {
|
||||
if (angular.element('#p' + $scope.paragraph.id + '_html').length) {
|
||||
try {
|
||||
$('#p'+$scope.paragraph.id+'_html').html($scope.paragraph.result.msg);
|
||||
angular.element('#p' + $scope.paragraph.id + '_html').html($scope.paragraph.result.msg);
|
||||
|
||||
$('#p'+$scope.paragraph.id+'_html').find('pre code').each(function(i, e) { hljs.highlightBlock(e); });
|
||||
} catch(err) {
|
||||
angular.element('#p' + $scope.paragraph.id + '_html').find('pre code').each(function(i, e) {
|
||||
hljs.highlightBlock(e);
|
||||
});
|
||||
} catch (err) {
|
||||
console.log('HTML rendering error %o', err);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -126,12 +128,16 @@ angular.module('zeppelinWebApp')
|
|||
if (!config.graph.scatter) {
|
||||
config.graph.scatter = {};
|
||||
}
|
||||
|
||||
if (config.enabled === undefined) {
|
||||
config.enabled = true;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.getIframeDimensions = function () {
|
||||
if ($scope.asIframe) {
|
||||
var paragraphid = '#' + $routeParams.paragraphId + '_container';
|
||||
var height = $(paragraphid).height();
|
||||
var height = angular.element(paragraphid).height();
|
||||
return height;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -266,6 +272,13 @@ angular.module('zeppelinWebApp')
|
|||
$scope.dirtyText = undefined;
|
||||
};
|
||||
|
||||
$scope.toggleEnableDisable = function () {
|
||||
$scope.paragraph.config.enabled = $scope.paragraph.config.enabled ? false : true;
|
||||
var newParams = angular.copy($scope.paragraph.settings.params);
|
||||
var newConfig = angular.copy($scope.paragraph.config);
|
||||
commitParagraph($scope.paragraph.title, $scope.paragraph.text, newConfig, newParams);
|
||||
};
|
||||
|
||||
$scope.moveUp = function() {
|
||||
$scope.$emit('moveParagraphUp', $scope.paragraph.id);
|
||||
};
|
||||
|
|
@ -471,7 +484,7 @@ angular.module('zeppelinWebApp')
|
|||
$scope.editor.focus();
|
||||
|
||||
autoAdjustEditorHeight(_editor.container.id);
|
||||
$(window).resize(function(){
|
||||
angular.element(window).resize(function() {
|
||||
autoAdjustEditorHeight(_editor.container.id);
|
||||
});
|
||||
|
||||
|
|
@ -602,7 +615,11 @@ angular.module('zeppelinWebApp')
|
|||
if ($scope.editor.completer && $scope.editor.completer.activated) { // if autocompleter is active
|
||||
} else {
|
||||
// fix ace editor focus issue in chrome (textarea element goes to top: -1000px after focused by cursor move)
|
||||
angular.element('#' + $scope.paragraph.id + '_editor > textarea').css('top', 0);
|
||||
if (parseInt(angular.element('#' + $scope.paragraph.id + '_editor > textarea').css('top').replace('px', '')) < 0) {
|
||||
var position = $scope.editor.getCursorPosition();
|
||||
var cursorPos = $scope.editor.renderer.$cursorLayer.getPixelPosition(position, true);
|
||||
angular.element('#' + $scope.paragraph.id + '_editor > textarea').css('top', cursorPos.top);
|
||||
}
|
||||
|
||||
var numRows;
|
||||
var currentRow;
|
||||
|
|
@ -636,7 +653,7 @@ angular.module('zeppelinWebApp')
|
|||
var editor = $scope.editor;
|
||||
var height = editor.getSession().getScreenLength() * editor.renderer.lineHeight + editor.renderer.scrollBar.getWidth();
|
||||
|
||||
$('#' + id).height(height.toString() + 'px');
|
||||
angular.element('#' + id).height(height.toString() + 'px');
|
||||
editor.resize();
|
||||
};
|
||||
|
||||
|
|
@ -670,7 +687,7 @@ angular.module('zeppelinWebApp')
|
|||
var position = $scope.editor.getCursorPosition();
|
||||
var lastCursorPosition = $scope.editor.renderer.$cursorLayer.getPixelPosition(position, true);
|
||||
|
||||
var calculatedCursorPosition = editorPosition.top + lastCursorPosition.top + 16*lastCursorMove;
|
||||
var calculatedCursorPosition = editorPosition.top + lastCursorPosition.top + lineHeight*lastCursorMove;
|
||||
|
||||
var scrollTargetPos;
|
||||
if (calculatedCursorPosition < scrollPosition + headerHeight + scrollTriggerEdgeMargin) {
|
||||
|
|
@ -685,7 +702,14 @@ angular.module('zeppelinWebApp')
|
|||
scrollTargetPos = documentHeight;
|
||||
}
|
||||
}
|
||||
angular.element('body').scrollTo(scrollTargetPos, {axis: 'y', interrupt: true, duration:200});
|
||||
|
||||
// cancel previous scroll animation
|
||||
var bodyEl = angular.element('body');
|
||||
bodyEl.stop();
|
||||
bodyEl.finish();
|
||||
|
||||
// scroll to scrollTargetPos
|
||||
bodyEl.scrollTo(scrollTargetPos, {axis: 'y', interrupt: true, duration:100});
|
||||
};
|
||||
|
||||
var setEditorHeight = function(id, height) {
|
||||
|
|
@ -739,11 +763,10 @@ angular.module('zeppelinWebApp')
|
|||
var row;
|
||||
if (cursorPos >= 0) {
|
||||
row = cursorPos;
|
||||
var column = 0;
|
||||
$scope.editor.gotoLine(row, 0);
|
||||
} else {
|
||||
row = $scope.editor.session.getLength() - 1;
|
||||
$scope.editor.gotoLine(row + 1, 0);
|
||||
row = $scope.editor.session.getLength();
|
||||
$scope.editor.gotoLine(row, 0);
|
||||
}
|
||||
$scope.scrollToCursor($scope.paragraph.id, 0);
|
||||
}
|
||||
|
|
@ -847,7 +870,7 @@ angular.module('zeppelinWebApp')
|
|||
clearUnknownColsFromGraphOption();
|
||||
// set graph height
|
||||
var height = $scope.paragraph.config.graph.height;
|
||||
$('#p'+$scope.paragraph.id+'_graph').height(height);
|
||||
angular.element('#p' + $scope.paragraph.id + '_graph').height(height);
|
||||
|
||||
if (!type || type === 'table') {
|
||||
setTable($scope.paragraph.result, refresh);
|
||||
|
|
@ -933,16 +956,16 @@ angular.module('zeppelinWebApp')
|
|||
|
||||
html += '</table>';
|
||||
|
||||
$('#p' + $scope.paragraph.id + '_table').html(html);
|
||||
$('#p' + $scope.paragraph.id + '_table').perfectScrollbar();
|
||||
angular.element('#p' + $scope.paragraph.id + '_table').html(html);
|
||||
angular.element('#p' + $scope.paragraph.id + '_table').perfectScrollbar();
|
||||
|
||||
// set table height
|
||||
var height = $scope.paragraph.config.graph.height;
|
||||
$('#p'+$scope.paragraph.id+'_table').height(height);
|
||||
angular.element('#p' + $scope.paragraph.id + '_table').height(height);
|
||||
};
|
||||
|
||||
var retryRenderer = function() {
|
||||
if ($('#p'+$scope.paragraph.id+'_table').length) {
|
||||
if (angular.element('#p' + $scope.paragraph.id + '_table').length) {
|
||||
try {
|
||||
renderTable();
|
||||
} catch(err) {
|
||||
|
|
@ -1076,7 +1099,7 @@ angular.module('zeppelinWebApp')
|
|||
};
|
||||
|
||||
var retryRenderer = function() {
|
||||
if ($('#p'+$scope.paragraph.id+'_'+type+' svg').length !== 0) {
|
||||
if (angular.element('#p' + $scope.paragraph.id + '_' + type + ' svg').length !== 0) {
|
||||
try {
|
||||
renderChart();
|
||||
} catch(err) {
|
||||
|
|
@ -1751,7 +1774,7 @@ angular.module('zeppelinWebApp')
|
|||
};
|
||||
|
||||
$scope.setGraphHeight = function() {
|
||||
var height = $('#p'+$scope.paragraph.id+'_graph').height();
|
||||
var height = angular.element('#p' + $scope.paragraph.id + '_graph').height();
|
||||
|
||||
var newParams = angular.copy($scope.paragraph.settings.params);
|
||||
var newConfig = angular.copy($scope.paragraph.config);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@
|
|||
border: 3px solid #DDDDDD;
|
||||
}
|
||||
|
||||
.paragraph .paragraphFooter {
|
||||
.paragraph .paragraphFooter {
|
||||
height: 9px;
|
||||
}
|
||||
|
||||
|
|
@ -182,6 +182,14 @@
|
|||
color: #333333;
|
||||
}
|
||||
|
||||
/*
|
||||
Paragraph Menu
|
||||
*/
|
||||
|
||||
.dropdown-menu > li > a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*
|
||||
Paragraph Title
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ limitations under the License.
|
|||
require : ['ace/ext/language_tools']
|
||||
}"
|
||||
ng-model="paragraph.text"
|
||||
ng-class="{'disable': paragraph.status == 'RUNNING' || paragraph.status == 'PENDING', 'paragraph-text--dirty' : dirtyText}">
|
||||
ng-class="{'disable': paragraph.status == 'RUNNING' || paragraph.status == 'PENDING', 'paragraph-text--dirty' : dirtyText !== undefined}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -410,7 +410,7 @@ limitations under the License.
|
|||
<!-- Run / Cancel button -->
|
||||
<span class="icon-control-play" style="cursor:pointer;color:#3071A9" tooltip-placement="top" tooltip="Run this paragraph (Shift+Enter)"
|
||||
ng-click="runParagraph(getEditorValue())"
|
||||
ng-show="paragraph.status!='RUNNING' && paragraph.status!='PENDING'"></span>
|
||||
ng-show="paragraph.status!='RUNNING' && paragraph.status!='PENDING' && paragraph.config.enabled"></span>
|
||||
<span class="icon-control-pause" style="cursor:pointer;color:#CD5C5C" tooltip-placement="top" tooltip="Cancel"
|
||||
ng-click="cancelParagraph()"
|
||||
ng-show="paragraph.status=='RUNNING' || paragraph.status=='PENDING'"></span>
|
||||
|
|
@ -418,9 +418,6 @@ limitations under the License.
|
|||
ng-click="toggleEditor()"></span>
|
||||
<span class="{{paragraph.config.tableHide ? 'icon-notebook' : 'icon-book-open'}}" style="cursor:pointer;" tooltip-placement="top" tooltip="{{(paragraph.config.tableHide ? 'Show' : 'Hide') + ' output'}}"
|
||||
ng-click="toggleOutput()"></span>
|
||||
<span style="cursor:pointer;"
|
||||
ng-click="saveParagraph()"
|
||||
ng-show="dirtyText"></span>
|
||||
<span class="dropdown navbar-right">
|
||||
<span class="icon-settings" style="cursor:pointer"
|
||||
data-toggle="dropdown"
|
||||
|
|
@ -428,56 +425,50 @@ limitations under the License.
|
|||
</span>
|
||||
<ul class="dropdown-menu" role="menu" style="width:200px;">
|
||||
<li>
|
||||
<a class="fa fa-arrows-h dropdown"> Width
|
||||
<form style="display:inline; margin-left:5px;">
|
||||
<select ng-model="paragraph.config.colWidth"
|
||||
class="selectpicker"
|
||||
ng-change="changeColWidth()"
|
||||
ng-options="col for col in colWidthOption"></select>
|
||||
</form>
|
||||
<a class="dropdown"><span class="fa fa-arrows-h"></span> Width
|
||||
<form style="display:inline; margin-left:5px;">
|
||||
<select ng-model="paragraph.config.colWidth"
|
||||
class="selectpicker"
|
||||
ng-change="changeColWidth()"
|
||||
ng-options="col for col in colWidthOption"></select>
|
||||
</form>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="icon-arrow-up" style="cursor:pointer"
|
||||
ng-click="moveUp()"> Move Up</a>
|
||||
<a ng-click="moveUp()"><span class="icon-arrow-up"></span> Move Up</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="icon-arrow-down" style="cursor:pointer"
|
||||
ng-click="moveDown()"> Move Down</a>
|
||||
<a ng-click="moveDown()"><span class="icon-arrow-down"></span> Move Down</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="icon-plus" style="cursor:pointer"
|
||||
ng-click="insertNew()"> Insert New</a>
|
||||
<a ng-click="insertNew()"><span class="icon-plus"></span> Insert New</a>
|
||||
</li>
|
||||
<li>
|
||||
<!-- paragraph handler -->
|
||||
<a class="fa fa-font" style="cursor:pointer"
|
||||
ng-click="hideTitle()"
|
||||
ng-show="paragraph.config.title"> Hide title</a>
|
||||
<a class="fa fa-font" style="cursor:pointer"
|
||||
ng-click="showTitle()"
|
||||
ng-show="!paragraph.config.title"> Show title</a>
|
||||
<a ng-click="hideTitle()"
|
||||
ng-show="paragraph.config.title"><span class="fa fa-font"></span> Hide title</a>
|
||||
<a ng-click="showTitle()"
|
||||
ng-show="!paragraph.config.title"><span class="fa fa-font"></span> Show title</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="fa fa-list-ol" style="cursor:pointer"
|
||||
ng-click="hideLineNumbers()"
|
||||
ng-show="paragraph.config.lineNumbers"> Hide line numbers</a>
|
||||
<a class="fa fa-list-ol" style="cursor:pointer"
|
||||
ng-click="showLineNumbers()"
|
||||
ng-show="!paragraph.config.lineNumbers"> Show line numbers</a>
|
||||
</li>
|
||||
|
||||
<li><a class="icon-share-alt" style="cursor:pointer"
|
||||
ng-click="goToSingleParagraph()"> Link this paragraph</a>
|
||||
<a ng-click="hideLineNumbers()"
|
||||
ng-show="paragraph.config.lineNumbers"><span class="fa fa-list-ol"></span> Hide line numbers</a>
|
||||
<a ng-click="showLineNumbers()"
|
||||
ng-show="!paragraph.config.lineNumbers"><span class="fa fa-list-ol"></span> Show line numbers</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="fa fa-eraser" style="cursor:pointer"
|
||||
ng-click="clearParagraphOutput()"> Clear output</a>
|
||||
<a ng-click="toggleEnableDisable()"><span class="icon-control-play"></span>
|
||||
{{paragraph.config.enabled ? "Disable" : "Enable"}} run</a>
|
||||
</li>
|
||||
<li>
|
||||
<a ng-click="goToSingleParagraph()"><span class="icon-share-alt"></span> Link this paragraph</a>
|
||||
</li>
|
||||
<li>
|
||||
<a ng-click="clearParagraphOutput()"><span class="fa fa-eraser"></span> Clear output</a>
|
||||
</li>
|
||||
<li>
|
||||
<!-- remove paragraph -->
|
||||
<a class="fa fa-times" style="cursor:pointer"
|
||||
ng-click="removeParagraph()"> Remove</a>
|
||||
<a ng-click="removeParagraph()"><span class="fa fa-times"></span> Remove</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
|
|
@ -487,5 +478,5 @@ limitations under the License.
|
|||
<div ng-show="!paragraph.config.tableHide && !viewOnly" id="{{paragraph.id}}_executionTime" class="executionTime" ng-bind-html="getExecutionTime()">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ body {
|
|||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
|
||||
color: #2c3e50;
|
||||
border-bottom: 1px solid #E5E5E5;
|
||||
z-index: 300;
|
||||
}
|
||||
|
||||
.editor,
|
||||
|
|
|
|||
|
|
@ -69,3 +69,7 @@ body {
|
|||
.lastEmptyParagraph {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.noteAction button.btn {
|
||||
border-radius: 4px !important;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ angular.module('zeppelinWebApp').service('baseUrlSrv', function() {
|
|||
|
||||
this.getWebsocketUrl = function() {
|
||||
var wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
return wsProtocol + '//' + location.hostname + ':' + this.getPort() + '/ws';
|
||||
return wsProtocol + '//' + location.hostname + ':' + this.getPort() + skipTrailingSlash(location.pathname) + '/ws';
|
||||
};
|
||||
|
||||
this.getRestApiBase = function() {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
angular.module('zeppelinWebApp').controller('NavCtrl', function($scope, $rootScope, $routeParams, notebookListDataFactory, websocketMsgSrv, arrayOrderingSrv) {
|
||||
angular.module('zeppelinWebApp').controller('NavCtrl', function($scope, $rootScope, $routeParams,
|
||||
notebookListDataFactory, websocketMsgSrv,
|
||||
arrayOrderingSrv) {
|
||||
/** Current list of notes (ids) */
|
||||
|
||||
var vm = this;
|
||||
|
|
@ -23,7 +25,7 @@ angular.module('zeppelinWebApp').controller('NavCtrl', function($scope, $rootSco
|
|||
vm.websocketMsgSrv = websocketMsgSrv;
|
||||
vm.arrayOrderingSrv = arrayOrderingSrv;
|
||||
|
||||
$('#notebook-list').perfectScrollbar({suppressScrollX: true});
|
||||
angular.element('#notebook-list').perfectScrollbar({suppressScrollX: true});
|
||||
|
||||
$scope.$on('setNoteMenu', function(event, notes) {
|
||||
notebookListDataFactory.setNotes(notes);
|
||||
|
|
|
|||
|
|
@ -14,41 +14,45 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
angular.module('zeppelinWebApp').controller('NotenameCtrl', function($scope, $rootScope, $routeParams, websocketMsgSrv) {
|
||||
angular.module('zeppelinWebApp').controller('NotenameCtrl', function($scope, $rootScope, $routeParams, websocketMsgSrv, $location) {
|
||||
var vm = this;
|
||||
vm.websocketMsgSrv = websocketMsgSrv;
|
||||
$scope.note = {};
|
||||
vm.createNote = function(){
|
||||
if(!vm.clone){
|
||||
vm.websocketMsgSrv.createNotebook($scope.note.notename);
|
||||
}else{
|
||||
var noteId = $routeParams.noteId;
|
||||
vm.websocketMsgSrv.cloneNotebook(noteId, $scope.note.notename);
|
||||
}
|
||||
|
||||
vm.createNote = function() {
|
||||
if (!vm.clone) {
|
||||
vm.websocketMsgSrv.createNotebook($scope.note.notename);
|
||||
} else {
|
||||
var noteId = $routeParams.noteId;
|
||||
vm.websocketMsgSrv.cloneNotebook(noteId, $scope.note.notename);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.$on('setNoteContent', function(event, note) {
|
||||
if(note !== undefined) {
|
||||
window.location = '#/notebook/' + note.id;
|
||||
console.log(note);
|
||||
//a hack, to make it run only after notebook creation
|
||||
//it should not run i.e in case of linking to the paragraph
|
||||
if (note && $location.path().indexOf(note.id) < 0) {
|
||||
$location.path('notebook/' + note.id);
|
||||
}
|
||||
});
|
||||
|
||||
vm.preVisible = function(clone){
|
||||
var generatedName = vm.generateName();
|
||||
$scope.note.notename = 'Note ' + generatedName;
|
||||
vm.clone = clone;
|
||||
$scope.$apply();
|
||||
vm.preVisible = function(clone) {
|
||||
var generatedName = vm.generateName();
|
||||
$scope.note.notename = 'Note ' + generatedName;
|
||||
vm.clone = clone;
|
||||
$scope.$apply();
|
||||
};
|
||||
|
||||
vm.generateName = function () {
|
||||
var DICTIONARY = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
|
||||
'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R',
|
||||
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ];
|
||||
var randIndex, name = '';
|
||||
for (var i = 0; i < 9; i++) {
|
||||
randIndex = Math.floor(Math.random() * 32);
|
||||
name += DICTIONARY[randIndex];
|
||||
}
|
||||
return name;
|
||||
};
|
||||
var DICTIONARY = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
|
||||
'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R',
|
||||
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ];
|
||||
var randIndex, name = '';
|
||||
for (var i = 0; i < 9; i++) {
|
||||
randIndex = Math.floor(Math.random() * 32);
|
||||
name += DICTIONARY[randIndex];
|
||||
}
|
||||
return name;
|
||||
};
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
<!--
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<div id="noteImportModal" class="modal fade" role="dialog"
|
||||
tabindex='-1'>
|
||||
<div class="modal-dialog">
|
||||
|
||||
<!-- Modal content-->
|
||||
<div class="modal-content" id="NoteImportCtrl" ng-init="NoteImportInit">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">Import new note</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="noteImportName">Import AS</label>
|
||||
<input placeholder="Note name" type="text" class="form-control" id="noteImportName"
|
||||
ng-model="note.noteImportName">
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-show="note.errorText">
|
||||
<div class="alert alert-danger">{{note.errorText}}</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group slide-left" ng-show="note.step1">
|
||||
<div class="display-inline">
|
||||
<a class="fa fa-cloud-upload import-file-upload" ng-click="uploadFile()">
|
||||
<p>Choose a JSON here</p>
|
||||
</a>
|
||||
</div>
|
||||
<div style="display: none">
|
||||
<input placeholder="Note name" type="file" class="form-control" id="noteImportFile"
|
||||
ng-model="note.importFile" onchange="angular.element(this).scope().importFile(this)">
|
||||
</div>
|
||||
<div class="display-inline">
|
||||
<a href="javascript:void(0);" ng-click="uploadURL()" class="fa fa-link">
|
||||
<p>Add from URL</p>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group slide-right" ng-show="note.step2">
|
||||
|
||||
<label for="noteImportUrl">URL</label>
|
||||
<input placeholder="Note name" type="text" class="form-control" id="noteImportUrl"
|
||||
ng-model="note.importUrl">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div ng-show="note.step2">
|
||||
<button type="button" id="importBackButton"
|
||||
class="btn btn-default"
|
||||
ng-click="noteimportctrl.importBack()">Back
|
||||
</button>
|
||||
<button type="button" id="importNoteButton"
|
||||
class="btn btn-default"
|
||||
ng-click="noteimportctrl.importNote()">Import Note
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('zeppelinWebApp').controller('NoteImportCtrl', function($scope, $timeout, websocketMsgSrv) {
|
||||
var vm = this;
|
||||
$scope.note = {};
|
||||
$scope.note.step1 = true;
|
||||
$scope.note.step2 = false;
|
||||
|
||||
vm.resetFlags = function() {
|
||||
$scope.note = {};
|
||||
$scope.note.step1 = true;
|
||||
$scope.note.step2 = false;
|
||||
angular.element('#noteImportFile').val('');
|
||||
};
|
||||
|
||||
$scope.uploadFile = function() {
|
||||
angular.element('#noteImportFile').click();
|
||||
};
|
||||
|
||||
$scope.importFile = function(element) {
|
||||
$scope.note.errorText = '';
|
||||
$scope.note.importFile = element.files[0];
|
||||
var file = $scope.note.importFile;
|
||||
var reader = new FileReader();
|
||||
|
||||
reader.onloadend = function() {
|
||||
vm.processImportJson(reader.result);
|
||||
};
|
||||
|
||||
if (file) {
|
||||
reader.readAsText(file);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.uploadURL = function() {
|
||||
$scope.note.errorText = '';
|
||||
$scope.note.step1 = false;
|
||||
$timeout(function() {
|
||||
$scope.note.step2 = true;
|
||||
}, 400);
|
||||
};
|
||||
|
||||
vm.importBack = function() {
|
||||
$scope.note.errorText = '';
|
||||
$timeout(function() {
|
||||
$scope.note.step1 = true;
|
||||
}, 400);
|
||||
$scope.note.step2 = false;
|
||||
};
|
||||
|
||||
vm.importNote = function() {
|
||||
$scope.note.errorText = '';
|
||||
if ($scope.note.importUrl) {
|
||||
jQuery.getJSON($scope.note.importUrl, function(result) {
|
||||
vm.processImportJson(result);
|
||||
}).fail(function() {
|
||||
$scope.note.errorText = 'Unable to Fetch URL';
|
||||
$scope.$apply();
|
||||
});
|
||||
}
|
||||
else {
|
||||
$scope.note.errorText = 'Enter URL';
|
||||
$scope.$apply();
|
||||
}
|
||||
};
|
||||
|
||||
vm.processImportJson = function(result) {
|
||||
if (typeof result !== 'object') {
|
||||
try {
|
||||
result = JSON.parse(result);
|
||||
} catch (e) {
|
||||
$scope.note.errorText = 'JSON parse exception';
|
||||
$scope.$apply();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
if (result.paragraphs && result.paragraphs.length > 0) {
|
||||
if (!$scope.note.noteImportName) {
|
||||
$scope.note.noteImportName = result.name;
|
||||
} else {
|
||||
result.name = $scope.note.noteImportName;
|
||||
}
|
||||
websocketMsgSrv.importNotebook(result);
|
||||
//angular.element('#noteImportModal').modal('hide');
|
||||
} else {
|
||||
$scope.note.errorText = 'Invalid JSON';
|
||||
}
|
||||
$scope.$apply();
|
||||
};
|
||||
|
||||
$scope.$on('setNoteMenu', function(event, notes) {
|
||||
vm.resetFlags();
|
||||
angular.element('#noteImportModal').modal('hide');
|
||||
});
|
||||
});
|
||||
|
|
@ -113,6 +113,15 @@ angular.module('zeppelinWebApp').service('websocketMsgSrv', function($rootScope,
|
|||
});
|
||||
},
|
||||
|
||||
importNotebook: function(notebook) {
|
||||
websocketEvents.sendNewEvent({
|
||||
op: 'IMPORT_NOTE',
|
||||
data: {
|
||||
notebook: notebook
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
isConnected: function(){
|
||||
return websocketEvents.isConnected();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,9 @@ limitations under the License.
|
|||
<div ng-controller="NotenameCtrl as notenamectrl">
|
||||
<div id="note-modal-container" ng-include src="'components/noteName-create/note-name-dialog.html'"></div>
|
||||
</div>
|
||||
<div ng-controller="NoteImportCtrl as noteimportctrl">
|
||||
<div id="note-import-container" ng-include src="'components/noteName-import/note-import-dialog.html'"></div>
|
||||
</div>
|
||||
<!-- build:js(.) scripts/oldieshim.js -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="bower_components/es5-shim/es5-shim.js"></script>
|
||||
|
|
@ -129,6 +132,7 @@ limitations under the License.
|
|||
<script src="components/navbar/navbar.controller.js"></script>
|
||||
<script src="components/ngescape/ngescape.directive.js"></script>
|
||||
<script src="components/noteName-create/notename.controller.js"></script>
|
||||
<script src="components/noteName-import/notenameImport.controller.js"></script>
|
||||
<script src="components/popover-html-unsafe/popover-html-unsafe.directive.js"></script>
|
||||
<script src="components/ngenter/ngenter.directive.js"></script>
|
||||
<script src="components/dropdowninput/dropdowninput.directive.js"></script>
|
||||
|
|
|
|||
|
|
@ -268,6 +268,10 @@ public class ZeppelinConfiguration extends XMLConfiguration {
|
|||
return getInt(ConfVars.ZEPPELIN_PORT);
|
||||
}
|
||||
|
||||
public String getServerContextPath() {
|
||||
return getString(ConfVars.ZEPPELIN_SERVER_CONTEXT_PATH);
|
||||
}
|
||||
|
||||
public String getKeyStorePath() {
|
||||
return getRelativeDir(
|
||||
String.format("%s/%s",
|
||||
|
|
@ -383,6 +387,7 @@ public class ZeppelinConfiguration extends XMLConfiguration {
|
|||
ZEPPELIN_HOME("zeppelin.home", "../"),
|
||||
ZEPPELIN_ADDR("zeppelin.server.addr", "0.0.0.0"),
|
||||
ZEPPELIN_PORT("zeppelin.server.port", 8080),
|
||||
ZEPPELIN_SERVER_CONTEXT_PATH("zeppelin.server.context.path", "/"),
|
||||
ZEPPELIN_SSL("zeppelin.ssl", false),
|
||||
ZEPPELIN_SSL_CLIENT_AUTH("zeppelin.ssl.client.auth", false),
|
||||
ZEPPELIN_SSL_KEYSTORE_PATH("zeppelin.ssl.keystore.path", "keystore"),
|
||||
|
|
|
|||
|
|
@ -294,21 +294,6 @@ public class Note implements Serializable, JobListener {
|
|||
}
|
||||
}
|
||||
|
||||
public List<Map<String, String>> generateParagraphsInfo (){
|
||||
List<Map<String, String>> paragraphsInfo = new LinkedList<>();
|
||||
synchronized (paragraphs) {
|
||||
for (Paragraph p : paragraphs) {
|
||||
Map<String, String> info = new HashMap<>();
|
||||
info.put("id", p.getId());
|
||||
info.put("status", p.getStatus().toString());
|
||||
info.put("started", p.getDateStarted().toString());
|
||||
info.put("finished", p.getDateFinished().toString());
|
||||
paragraphsInfo.add(info);
|
||||
}
|
||||
}
|
||||
return paragraphsInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all paragraphs sequentially.
|
||||
*
|
||||
|
|
@ -334,14 +319,13 @@ public class Note implements Serializable, JobListener {
|
|||
Paragraph p = getParagraph(paragraphId);
|
||||
p.setNoteReplLoader(replLoader);
|
||||
p.setListener(jobListenerFactory.getParagraphJobListener(this));
|
||||
logger.info("Note Run Paragraph=" + p);
|
||||
Interpreter intp = replLoader.get(p.getRequiredReplName());
|
||||
logger.info("Note Run intp=" + intp);
|
||||
if (intp == null) {
|
||||
throw new InterpreterException("Interpreter " + p.getRequiredReplName() + " not found");
|
||||
}
|
||||
logger.info("Note Run intp=" + intp);
|
||||
intp.getScheduler().submit(p);
|
||||
if ((Boolean) p.getConfig().get("enabled")) {
|
||||
intp.getScheduler().submit(p);
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> completion(String paragraphId, String buffer, int cursor) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ import org.apache.zeppelin.display.GUI;
|
|||
import org.apache.zeppelin.display.Input;
|
||||
import org.apache.zeppelin.interpreter.*;
|
||||
import org.apache.zeppelin.interpreter.Interpreter.FormType;
|
||||
import org.apache.zeppelin.interpreter.InterpreterResult.Code;
|
||||
import org.apache.zeppelin.interpreter.InterpreterResult.Type;
|
||||
import org.apache.zeppelin.scheduler.Job;
|
||||
import org.apache.zeppelin.scheduler.JobListener;
|
||||
import org.slf4j.Logger;
|
||||
|
|
@ -205,13 +207,22 @@ public class Paragraph extends Job implements Serializable, Cloneable {
|
|||
}
|
||||
logger().debug("RUN : " + script);
|
||||
InterpreterResult ret = repl.interpret(script, getInterpreterContext());
|
||||
|
||||
if (Code.KEEP_PREVIOUS_RESULT == ret.code()) {
|
||||
return getReturn();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean jobAbort() {
|
||||
Interpreter repl = getRepl(getRequiredReplName());
|
||||
repl.cancel(getInterpreterContext());
|
||||
Job job = repl.getScheduler().removeFromWaitingQueue(getId());
|
||||
if (job != null) {
|
||||
job.setStatus(Status.ABORT);
|
||||
} else {
|
||||
repl.cancel(getInterpreterContext());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -214,11 +214,12 @@ public class VFSNotebookRepo implements NotebookRepo {
|
|||
throw new IOException(noteDir.getName().toString() + " is not a directory");
|
||||
}
|
||||
|
||||
FileObject noteJson = noteDir.resolveFile("note.json", NameScope.CHILD);
|
||||
FileObject noteJson = noteDir.resolveFile(".note.json", NameScope.CHILD);
|
||||
// false means not appending. creates file if not exists
|
||||
OutputStream out = noteJson.getContent().getOutputStream(false);
|
||||
out.write(json.getBytes(conf.getString(ConfVars.ZEPPELIN_ENCODING)));
|
||||
out.close();
|
||||
noteJson.moveTo(noteDir.resolveFile("note.json", NameScope.CHILD));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ import static org.junit.Assert.assertTrue;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
|
@ -47,8 +49,11 @@ import org.junit.After;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class NotebookTest implements JobListenerFactory{
|
||||
private static final Logger logger = LoggerFactory.getLogger(NotebookTest.class);
|
||||
|
||||
private File tmpDir;
|
||||
private ZeppelinConfiguration conf;
|
||||
|
|
@ -95,6 +100,9 @@ public class NotebookTest implements JobListenerFactory{
|
|||
|
||||
// run with defatul repl
|
||||
Paragraph p1 = note.addParagraph();
|
||||
Map config = p1.getConfig();
|
||||
config.put("enabled", true);
|
||||
p1.setConfig(config);
|
||||
p1.setText("hello world");
|
||||
note.run(p1.getId());
|
||||
while(p1.isTerminated()==false || p1.getResult()==null) Thread.yield();
|
||||
|
|
@ -102,6 +110,7 @@ public class NotebookTest implements JobListenerFactory{
|
|||
|
||||
// run with specific repl
|
||||
Paragraph p2 = note.addParagraph();
|
||||
p2.setConfig(config);
|
||||
p2.setText("%mock2 hello world");
|
||||
note.run(p2.getId());
|
||||
while(p2.isTerminated()==false || p2.getResult()==null) Thread.yield();
|
||||
|
|
@ -155,6 +164,9 @@ public class NotebookTest implements JobListenerFactory{
|
|||
|
||||
// run with default repl
|
||||
Paragraph p1 = note.addParagraph();
|
||||
Map config = p1.getConfig();
|
||||
config.put("enabled", true);
|
||||
p1.setConfig(config);
|
||||
p1.setText("hello world");
|
||||
note.persist();
|
||||
|
||||
|
|
@ -166,6 +178,9 @@ public class NotebookTest implements JobListenerFactory{
|
|||
public void testClearParagraphOutput() throws IOException, SchedulerException{
|
||||
Note note = notebook.createNote();
|
||||
Paragraph p1 = note.addParagraph();
|
||||
Map config = p1.getConfig();
|
||||
config.put("enabled", true);
|
||||
p1.setConfig(config);
|
||||
p1.setText("hello world");
|
||||
note.run(p1.getId());
|
||||
|
||||
|
|
@ -181,10 +196,14 @@ public class NotebookTest implements JobListenerFactory{
|
|||
public void testRunAll() throws IOException {
|
||||
Note note = notebook.createNote();
|
||||
note.getNoteReplLoader().setInterpreters(factory.getDefaultInterpreterSettingList());
|
||||
|
||||
Paragraph p1 = note.addParagraph();
|
||||
Map config = p1.getConfig();
|
||||
config.put("enabled", true);
|
||||
p1.setConfig(config);
|
||||
p1.setText("p1");
|
||||
Paragraph p2 = note.addParagraph();
|
||||
Map config1 = p2.getConfig();
|
||||
p2.setConfig(config1);
|
||||
p2.setText("p2");
|
||||
assertEquals(null, p2.getResult());
|
||||
note.runAll();
|
||||
|
|
@ -200,17 +219,20 @@ public class NotebookTest implements JobListenerFactory{
|
|||
note.getNoteReplLoader().setInterpreters(factory.getDefaultInterpreterSettingList());
|
||||
|
||||
Paragraph p = note.addParagraph();
|
||||
Map config = new HashMap<String, Object>();
|
||||
p.setConfig(config);
|
||||
p.setText("p1");
|
||||
Date dateFinished = p.getDateFinished();
|
||||
assertNull(dateFinished);
|
||||
|
||||
// set cron scheduler, once a second
|
||||
Map<String, Object> config = note.getConfig();
|
||||
config = note.getConfig();
|
||||
config.put("enabled", true);
|
||||
config.put("cron", "* * * * * ?");
|
||||
note.setConfig(config);
|
||||
notebook.refreshCron(note.id());
|
||||
Thread.sleep(1*1000);
|
||||
|
||||
|
||||
// remove cron scheduler.
|
||||
config.put("cron", null);
|
||||
note.setConfig(config);
|
||||
|
|
@ -301,46 +323,35 @@ public class NotebookTest implements JobListenerFactory{
|
|||
Note note = notebook.createNote();
|
||||
note.getNoteReplLoader().setInterpreters(factory.getDefaultInterpreterSettingList());
|
||||
|
||||
Paragraph p1 = note.addParagraph();
|
||||
p1.setText("p1");
|
||||
Paragraph p2 = note.addParagraph();
|
||||
p2.setText("p2");
|
||||
Paragraph p3 = note.addParagraph();
|
||||
p3.setText("p3");
|
||||
Paragraph p4 = note.addParagraph();
|
||||
p4.setText("p4");
|
||||
ArrayList<Paragraph> paragraphs = new ArrayList<>();
|
||||
for (int i = 0; i < 100; i++) {
|
||||
Paragraph tmp = note.addParagraph();
|
||||
tmp.setText("p" + tmp.getId());
|
||||
paragraphs.add(tmp);
|
||||
}
|
||||
|
||||
/* all jobs are ready to run */
|
||||
assertEquals(Job.Status.READY, p1.getStatus());
|
||||
assertEquals(Job.Status.READY, p2.getStatus());
|
||||
assertEquals(Job.Status.READY, p3.getStatus());
|
||||
assertEquals(Job.Status.READY, p4.getStatus());
|
||||
for (Paragraph p : paragraphs) {
|
||||
assertEquals(Job.Status.READY, p.getStatus());
|
||||
}
|
||||
|
||||
/* run all */
|
||||
note.runAll();
|
||||
|
||||
/* all are pending in the beginning (first one possibly started)*/
|
||||
assertTrue(p1.getStatus() == Job.Status.PENDING || p1.getStatus() == Job.Status.RUNNING);
|
||||
assertEquals(Job.Status.PENDING, p2.getStatus());
|
||||
assertEquals(Job.Status.PENDING, p3.getStatus());
|
||||
assertEquals(Job.Status.PENDING, p4.getStatus());
|
||||
while (paragraphs.get(0).getStatus() != Status.FINISHED) Thread.yield();
|
||||
|
||||
/* wait till first job is terminated and second starts running */
|
||||
while(p1.isTerminated() == false || (p2.getStatus() == Job.Status.PENDING)) Thread.yield();
|
||||
|
||||
assertEquals(Job.Status.FINISHED, p1.getStatus());
|
||||
assertEquals(Job.Status.RUNNING, p2.getStatus());
|
||||
assertEquals(Job.Status.PENDING, p3.getStatus());
|
||||
assertEquals(Job.Status.PENDING, p4.getStatus());
|
||||
|
||||
/* restart interpreter */
|
||||
factory.restart(note.getNoteReplLoader().getInterpreterSettings().get(0).id());
|
||||
|
||||
/* pending and running jobs have been aborted */
|
||||
assertEquals(Job.Status.FINISHED, p1.getStatus());
|
||||
assertEquals(Job.Status.ABORT, p2.getStatus());
|
||||
assertEquals(Job.Status.ABORT, p3.getStatus());
|
||||
assertEquals(Job.Status.ABORT, p4.getStatus());
|
||||
boolean isAborted = false;
|
||||
for (Paragraph p : paragraphs) {
|
||||
logger.debug(p.getStatus().name());
|
||||
if (isAborted) {
|
||||
assertEquals(Job.Status.ABORT, p.getStatus());
|
||||
}
|
||||
if (p.getStatus() == Status.ABORT) {
|
||||
isAborted = true;
|
||||
}
|
||||
}
|
||||
|
||||
assertTrue(isAborted);
|
||||
}
|
||||
|
||||
private void delete(File file){
|
||||
|
|
@ -355,7 +366,7 @@ public class NotebookTest implements JobListenerFactory{
|
|||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JobListener getParagraphJobListener(Note note) {
|
||||
return new JobListener(){
|
||||
|
|
|
|||
|
|
@ -19,11 +19,10 @@ package org.apache.zeppelin.notebook.repo;
|
|||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.zeppelin.conf.ZeppelinConfiguration;
|
||||
|
|
@ -34,10 +33,8 @@ import org.apache.zeppelin.interpreter.mock.MockInterpreter1;
|
|||
import org.apache.zeppelin.interpreter.mock.MockInterpreter2;
|
||||
import org.apache.zeppelin.notebook.JobListenerFactory;
|
||||
import org.apache.zeppelin.notebook.Note;
|
||||
import org.apache.zeppelin.notebook.NoteInfo;
|
||||
import org.apache.zeppelin.notebook.Notebook;
|
||||
import org.apache.zeppelin.notebook.Paragraph;
|
||||
import org.apache.zeppelin.notebook.repo.NotebookRepoSync;
|
||||
import org.apache.zeppelin.scheduler.Job;
|
||||
import org.apache.zeppelin.scheduler.Job.Status;
|
||||
import org.apache.zeppelin.scheduler.JobListener;
|
||||
|
|
@ -149,6 +146,9 @@ public class NotebookRepoSyncTest implements JobListenerFactory{
|
|||
/* create note */
|
||||
Note note = notebookSync.createNote();
|
||||
Paragraph p1 = note.addParagraph();
|
||||
Map config = p1.getConfig();
|
||||
config.put("enabled", true);
|
||||
p1.setConfig(config);
|
||||
p1.setText("hello world");
|
||||
|
||||
/* new paragraph exists in note instance */
|
||||
|
|
|
|||
Loading…
Reference in a new issue