blob: c3f726a499a08eeaec434e9c4c35d0387e73121f [file] [log] [blame]
<!DOCTYPE html>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.
-->
<html>
<head>
<title>Data Model - Apache Blur (Incubator) Documentation</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap -->
<link href="resources/css/bootstrap.min.css" rel="stylesheet" media="screen">
<link href="resources/css/bs-docs.css" rel="stylesheet" media="screen">
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="http://incubator.apache.org/blur">Apache Blur (Incubator)</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="index.html">Main</a></li>
<li><a href="getting-started.html">Getting Started</a></li>
<li><a href="platform.html">Platform</a></li>
<li class="active"><a href="data-model.html">Data Model</a></li>
<li><a href="cluster-setup.html">Cluster Setup</a></li>
<li><a href="using-blur.html">Using Blur</a></li>
<li><a href="Blur.html">Blur API</a></li>
<li><a href="console.html">Console</a></li>
</ul>
</div>
</div>
</div>
<div class="container bs-docs-container">
<div class="row">
<div class="col-md-3">
<div class="bs-sidebar hidden-print affix" role="complementary">
<ul class="nav bs-sidenav">
<li>
<a href="#structure">Structure</a>
<ul class="nav">
<li><a href="#columns">Columns</a></li>
<li><a href="#records">Records</a></li>
<li><a href="#rows">Rows</a></li>
</ul>
</li>
<li>
<a href="#querying">Querying</a>
<ul class="nav">
<li><a href="#row_query">Row Query</a></li>
<li><a href="#text_query">Text</a></li>
<li><a href="#string_query">String</a></li>
<li><a href="#numeric_query">Numeric</a></li>
<li><a href="#date_query">Date</a></li>
<li><a href="#spatial_query">Spatial</a></li>
</ul>
</li>
<li>
<a href="#types">Types</a>
<ul class="nav">
<li><a href="#text_type">Text</a></li>
<li><a href="#string_type">String</a></li>
<li><a href="#long_type">Long</a></li>
<li><a href="#int_type">Integer</a></li>
<li><a href="#float_type">Float</a></li>
<li><a href="#double_type">Double</a></li>
<li><a href="#date_type">Date</a></li>
<li><a href="#stored_type">Stored</a></li>
<li><a href="#spatial_type">Spatial</a>
<ul class="nav">
<li><a href="#spatial_pointvector">&nbsp;&nbsp;Point Vector</a></li>
<li><a href="#spatial_termprefix">&nbsp;&nbsp;Term Prefix</a></li>
<li><a href="#spatial_recursiveprefix">&nbsp;&nbsp;Recursive Prefix</a></li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#custom_types">Custom Types</a>
<ul class="nav">
<li><a href="#custom_types_creating">Creating</a></li>
<li><a href="#custom_types_distributing">Distributing</a></li>
<li><a href="#custom_types_using">Using</a>
<ul class="nav">
<li><a href="#custom_types_using_cluster">&nbsp;&nbsp;Cluster Wide</a></li>
<li><a href="#custom_types_using_table">&nbsp;&nbsp;Single Table</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
<div class="col-md-9" role="main">
<section>
<div class="page-header">
<h1 id="structure">Data Structure</h1>
</div>
<p class="lead">
Blur is a table based query system. So within a single shard cluster there can be many different tables, each with a different schema, shard size, analyzers, etc. Each table contains Rows. A Row contains a row id (Lucene StringField internally) and many Records. A record has a record id (Lucene StringField internally), a family (Lucene StringField internally), and many Columns. A column contains a name and value, both are Strings in the API but the value can be interpreted as different types. All base Lucene Field types are supported, Text, String, Long, Int, Double, and Float.
</p>
<p>Starting with the most basic structure and building on it.</p>
<h3 id="columns">Columns</h3>
<p>
Columns contain a name and value, both are strings in the API but can be interpreted as an Integer, Float, Long, Double, String, or Text. All Column types default to Text and will be analyzed during the indexing process.
</p>
<pre><code class="json">Column {"name" => "value"}</code></pre>
<h3 id="records">Records</h3>
<p>
Record contains a Record Id, Family, and one or more Columns
</p>
<pre><code class="json">Record {
"recordId" => "1234",
"family" => "family1",
"columns" => [
Column {"column1" => "value1"},
Column {"column2" => "value2"},
Column {"column2" => "value3"},
Column {"column3" => "value4"}
]
}</code></pre>
<div class="bs-callout bs-callout-info"><h4>Quick Tip!</h4><p>The column names do not have to be unique within the Record. So you can treat multiple Columns with the same name as an array of values. Also the order of the values will be maintained.</p></div>
<h3 id="rows">Rows</h3>
<p>
Rows contain a row id and a list of Records.
</p>
<pre><code class="json">Row {
"id" => "r-5678",
"records" => [
Record {
"recordId" => "1234",
"family" => "family1",
"columns" => [
Column {"column1" => "value1"},
Column {"column2" => "value2"},
Column {"column2" => "value3"},
Column {"column3" => "value4"}
]
},
Record {
"recordId" => "9012",
"family" => "family1",
"columns" => [
Column {"column1" => "value1"}
]
},
Record {
"recordId" => "4321",
"family" => "family2",
"columns" => [
Column {"column16" => "value1"}
]
}
]
}</code></pre>
</section>
<section>
<div class="page-header">
<h1 id="querying">Querying</h1>
<p>
All queries follow the basic Lucene query syntax see (<a href="http://lucene.apache.org/core/4_4_0/queryparser/org/apache/lucene/queryparser/classic/package-summary.html">http://lucene.apache.org/core/4_4_0/queryparser/org/apache/lucene/queryparser/classic/package-summary.html</a>)
for an extensive explanation on the syntax.
</p>
<p>
All queries can have boolean logic like:
<pre><code class="json">+docs.body:hadoop +docs.author:jon</code></pre>
</p><p>
Which is the same as:
<pre><code class="json">docs.body:hadoop AND docs.author:jon</code></pre>
</p>
<h3 id="row_query">Row Queries</h3>
<p>
Row queries allow you to execute queries across Records within the same Row. Row queries are a similar idea to an inner join.
Let's say you want to find all the Rows that contain a Record with the family &quot;author&quot; and has a &quot;name&quot; Column that has that contains a term &quot;Jon&quot; and another Record with the family &quot;docs&quot; and has a &quot;body&quot; Column with a term of &quot;Hadoop&quot;.
<pre><code class="json">+&lt;author.name:Jon&gt; +&lt;docs.body:Hadoop&gt;</code></pre>
</p>
<p>
The meaning of the modifier on the outside of the &lt; indicates how you want Rows with matching Records
handled. In the case above, we've asked for Blur to include all Rows that match the criteria. However,
we could also have negated Rows with matching Records as well. Suppose, we're interested in books that
contain Hadoop but we happen to already own the one written by Jon, so we'd like to exclude them:
<pre><code class="json">-&lt;author.name:Jon&gt; +&lt;docs.body:Hadoop&gt;</code></pre>
</p>
<p>
So far, we've included only simple term queries inside the &lt; &gt; operators, but they support full
query expressions too. Suppose our previous query excluded to many good books because of our author criteria.
Well, we happen to know that the book we have was written by Jon in Atlanta, so let's further limit that part
of our criteria:
<pre><code class="json">-&lt;+author.name:Jon +author.city:Atlanta&gt; +&lt;docs.body:Hadoop&gt;</code></pre>
Seeing that positive (+) criteria inside the negated clause can be confusing, so let's "read" what we're asking
for from the inside out. First, the record criteria - find any Row that contains a Record with an author named
Jon AND in the city of Atlanta. Now, the negation (-) outside the &lt; says that we want to take all Rows
that match that criteria and exclude them from our results.
</p>
<h3 id="text_query">Text</h3>
<p>Text fields are analyzed with Lucene's standard analyzers, which mean that the string is broken down into terms
and the terms capitalization is removed as well as any special punctuation. See Lucene's documentation for further explanation.
</p>
<h4>Examples:</h4>
<p>
To run a query to find all the rows that contain a column with a term of &quot;hadoop&quot; where the family is &quot;docs&quot; and the column is &quot;body&quot;.
<pre><code class="json">docs.body:hadoop</code></pre>
</p>
<p>
To run a query to find all the rows that contain a column with a term of &quot;hadoop&quot; and &quot;awesome&quot; where the family is &quot;docs&quot; and the column is &quot;body&quot;.
<pre><code class="json">docs.body:(+hadoop +awesome)</code></pre>
</p>
<p>
To run a query to find all the rows that contain a column with a phrase of &quot;hadoop is awesome&quot; where the family is &quot;docs&quot; and the column is &quot;body&quot;.
<pre><code class="json">docs.body:&quot;hadoop is awesome&quot;</code></pre>
</p>
<p>
To run a query to find all the rows that contain a column with a word of &quot;hadoop&quot; and we want to deal with misspellings (or a Fuzzy query) where the family is &quot;docs&quot; and the column is &quot;body&quot;.
<pre><code class="json">docs.body:hadoop~</code></pre>
</p>
<p>
To run a query to find all the rows that contain a column with a word that matches a wildcard pattern of &quot;h*d?op&quot; where the family is &quot;docs&quot; and the column is &quot;body&quot;.
<pre><code class="json">docs.body:h*d?op</code></pre>
</p>
<h3 id="string_query">String</h3>
<p>String fields are indexed Columns that are not analyzed they are indexed as is. Do not use String fields for
large amount of text, this will increase the size of your index and probably not give you the desired behavior.
So given the string "Hadoop" and "hadoop", these will be indexed as two different term because the String field
is case sensitive. Also if the string contains "The cow jumps over the moon." the single term that will be placed
into the index is "The cow jumps over the moon." as a single string. This field type is normally used for id or
type lookups.
</p>
<h4>Examples:</h4>
<p>
To run a query to find all the rows that contain a column with a term of &quot;Hadoop&quot; where the family is &quot;docs&quot; and the column is &quot;type&quot;.
<pre><code class="json">docs.type:Hadoop</code></pre>
</p>
<h3 id="numeric_query">Numeric</h3>
<p>The numerics types are:
<ul>
<li>int</li>
<li>long</li>
<li>float</li>
<li>double</li>
</ul>
All numerics types can perform two types of queries:
<ul>
<li>Exact Match</li>
<li>Range</li>
</ul>
</p>
<h4>Examples:</h4>
<p>
To run a query to find all the rows that contain a column with a value of &quot;12345&quot; where the family is &quot;docs&quot; and the column is &quot;id&quot;.
<pre><code class="json">docs.id:12345</code></pre>
</p>
<p>
To run a query to find all the rows that contain a column with a starting value of &quot;12345&quot; and an ending values of &quot;54321&quot; where the family is &quot;docs&quot; and the column is &quot;id&quot;.
<pre><code class="json">docs.id:[12345 TO 54321]</code></pre>
</p>
<p>
To run a query to find all the rows that contain a column with a value less than &quot;12345&quot; where the family is &quot;docs&quot; and the column is &quot;id&quot;.
<pre><code class="json">docs.id:[MIN TO 12345}</code></pre>
</p>
<p>
To run a query to find all the rows that contain a column with a value less than or equal to &quot;12345&quot; where the family is &quot;docs&quot; and the column is &quot;id&quot;.
<pre><code class="json">docs.id:[MIN TO 12345]</code></pre>
</p>
<p>
To run a query to find all the rows that contain a column with a value great than to &quot;12345&quot; where the family is &quot;docs&quot; and the column is &quot;id&quot;.
<pre><code class="json">docs.id:{12345 TO MAX]</code></pre>
</p>
<p>
To run a query to find all the rows that contain a column with a value great than or equal to &quot;12345&quot; where the family is &quot;docs&quot; and the column is &quot;id&quot;.
<pre><code class="json">docs.id:[12345 TO MAX]</code></pre>
</p>
<h3 id="date_query">Date</h3>
<p>Date types are basically a long field type with a date parser built-in.
The date type can perform two types of queries:
<ul>
<li>Exact Match</li>
<li>Range</li>
</ul>
</p>
<h4>Examples:</h4>
<p>
To run a query to find all the rows that contain a column with a value of &quot;2012-09-11&quot; where the family is &quot;docs&quot; and the column is &quot;published_date&quot;.
<pre><code class="json">docs.published_date:2013-09-11</code></pre>
</p>
<p>
To run a query to find all the rows that contain a column with a starting value of &quot;2012-09-11&quot; and an ending values of &quot;2013-09-11&quot; where the family is &quot;docs&quot; and the column is &quot;published_date&quot;.
<pre><code class="json">docs.published_date:[2012-09-11 TO 2013-09-11]</code></pre>
</p>
<h3 id="spatial_query">Spatial</h3>
<p>
Spatial queries are supported through the Lucene spatial module. There are currently three
different types of strategies:
<ul>
<li>Point Vector</li>
<li>Term Query Prefix Tree</li>
<li>Recursive Prefix Tree</li>
</ul>
Currently all of the built in spatial types are using a GEO spatial context, meaning the assumed
coordinates are on the planet Earth. Each of these strategies support different indexing features
such as the shapes they can index, the shapes they can query with, and the operations they
support during the query. See the type section below to get a list of supported operations and
shapes per strategy.
</p>
<h4>Examples:</h4>
<p>
To run a query to find all the rows that contain a location within 10 km (0.089932 10 km in degrees) of gis coordinate &quot;33.0, -88.0&quot; where the family is &quot;docs&quot; and the column is &quot;location&quot;.
<pre><code class="json">docs.location:"Intersects(Circle(33.0, -88.0 d=0.089932))"</code></pre>
</p>
<p>
To run a query to find all the rows that contain a location within 10 km of gis coordinate &quot;33.0, -88.0&quot; where the family is &quot;docs&quot; and the column is &quot;location&quot;.
<pre><code class="json">docs.location:"Intersects(Circle(33.0, -88.0 d=10.0km))"</code></pre>
</p>
<p>
To run a query to find all the rows that contain a location within 10 miles of gis coordinate &quot;33.0, -88.0&quot; where the family is &quot;docs&quot; and the column is &quot;location&quot;.
<pre><code class="json">docs.location:"Intersects(Circle(33.0, -88.0 d=10.0m))"</code></pre>
</p>
</div>
</section>
<section>
<div class="page-header">
<h1 id="types">Types</h1>
<h3 id="text_type">Text</h3>
<p>
The Text Type has the type name of:
<pre><code class="json">text</code></pre>
<h5>Property Options:</h5>
<ul>
<li>&quot;stopWordPath&quot; -Optional- default value is no stop words. This should be a HDFS path.
<br/>This will load stop words into the StandardAnalyzer for this field, one term per line.</li>
<li>&quot;analyzerClass&quot; -Optional- default value is a standard analyzer with no stop words.<br/>This could be any Analyzer class that has a default constructor or one that takes a Lucene Version enum.</li>
</ul>
</p>
<h3 id="string_type">String</h3>
<p>
The String Type has the type name of:
<pre><code class="json">string</code></pre>
<h5>Property Options:</h5>
<ul>
<li>None</li>
</ul>
</p>
<h3 id="long_type">Long</h3>
<p>
The Long Type has the type name of:
<pre><code class="json">long</code></pre>
<h5>Property Options:</h5>
<ul>
<li>&quot;numericPrecisionStep&quot; -Optional- default value is &quot;4&quot;</li>
</ul>
</p>
<h3 id="int_type">Integer</h3>
<p>
The Integer Type has the type name of:
<pre><code class="json">int</code></pre>
<h5>Property Options:</h5>
<ul>
<li>&quot;numericPrecisionStep&quot; -Optional- default value is &quot;4&quot;</li>
</ul>
</p>
<h3 id="float_type">Float</h3>
<p>
The Float Type has the type name of:
<pre><code class="json">float</code></pre>
<h5>Property Options:</h5>
<ul>
<li>&quot;numericPrecisionStep&quot; -Optional- default value is &quot;4&quot;</li>
</ul>
</p>
<h3 id="double_type">Double</h3>
<p>
The Double Type has the type name of:
<pre><code class="json">double</code></pre>
<h5>Property Options:</h5>
<ul>
<li>&quot;numericPrecisionStep&quot; -Optional- default value is &quot;4&quot;</li>
</ul>
</p>
<h3 id="date_type">Date</h3>
<p>
The Date Type has the type name of:
<pre><code class="json">date</code></pre>
<h5>Property Options:</h5>
<ul>
<li>&quot;dateFormat&quot; -Required- Examples: &quot;yyyy-MM-dd&quot;, &quot;MM/dd/yyyy&quot; or anything that SimpleDateFormat can parse.</li>
<li>&quot;timeUnit&quot; -Optional- Default is SECONDS. Other options (DAYS, HOURS, MINUTES, SECONDS, MILLISECONDS)</li>
<li>&quot;numericPrecisionStep&quot; -Optional- default value is &quot;4&quot;</li>
</ul>
</p>
<h3 id="stored_type">Stored</h3>
<p>
The Stored Type has the type name of:
<pre><code class="json">stored</code></pre>
<h5>Property Options:</h5>
<ul>
<li>None</li>
</ul>
</p>
<h3 id="spatial_type">Spatial</h3>
<p></p>
<h4 id="spatial_pointvector">Point Vector</h4>
<p>
The Point Vector Spatial Type has the type name of:
<pre><code class="json">geo-pointvector</code></pre>
<h5>Property Options:</h5>
<ul>
<li>None</li>
</ul>
<h5>Supported Indexing Shapes:</h5>
<ul>
<li>Point</li>
</ul>
<h5>Supported Querying Shapes:</h5>
<ul>
<li>Circle</li>
<li>Rectangle</li>
</ul>
<h5>Supported Querying Operations:</h5>
<ul>
<li>Intersects</li>
</ul>
</p>
<h4 id="spatial_termprefix">Term Prefix</h4>
<p>
The Term Prefix Spatial Type has the type name of:
<pre><code class="json">geo-termprefix</code></pre>
<h5>Property Options:</h5>
<ul>
<li>&quot;spatialPrefixTree&quot; can either equal to &quot;GeohashPrefixTree&quot; or &quot;QuadPrefixTree&quot;</li>
<li>&quot;maxLevels&quot; -Optional- default value is &quot;11&quot;</li>
</ul>
<h5>Supported Indexing Shapes:</h5>
<ul>
<li>Point</li>
</ul>
<h5>Supported Querying Shapes:</h5>
<ul>
<li>Circle</li>
<li>Rectangle</li>
</ul>
<h5>Supported Querying Operations:</h5>
<ul>
<li>Intersects</li>
</ul>
</p>
<h4 id="spatial_recursiveprefix">Recursive Prefix</h4>
<p>
The Term Prefix Spatial Type has the type name of:
<pre><code class="json">geo-recursiveprefix</code></pre>
<h5>Property Options:</h5>
<ul>
<li>&quot;spatialPrefixTree&quot; can either equal to &quot;GeohashPrefixTree&quot; or &quot;QuadPrefixTree&quot;</li>
<li>&quot;maxLevels&quot; -Optional- default value is &quot;11&quot;</li>
</ul>
<h5>Supported Indexing Shapes:</h5>
<ul>
<li>Point</li>
<li>Circle</li>
<li>Rectangle</li>
</ul>
<h5>Supported Querying Shapes:</h5>
<ul>
<li>Circle</li>
<li>Rectangle</li>
</ul>
<h5>Supported Querying Operations:</h5>
<ul>
<li>IsDisjointTo</li>
<li>Intersects</li>
<li>IsWithin</li>
<li>Contains</li>
</ul>
</p>
</div>
</section>
<section>
<div class="page-header">
<h1 id="custom_types">Custom Types</h1>
</div>
<p class="lead">Custom types in Blur allow you to create your own types in Lucene
as well as plugging into the query parser so that you can use your custom type.</p>
<h3 id="custom_types_creating">Creating</h3>
<p>
You will need to extend the "org.apache.blur.analysis.FieldTypeDefinition" class found in the blur-query module. If you need to use a different Analyzer than the StandardAnalyzer used in the "text" type just extend the "org.apache.blur.analysis.type.TextFieldTypeDefinition" and make the appropriate changes.
</p>
<p>
For types that require custom query parsing or custom "org.apache.lucene.index.IndexableField" manipulation without the use of an Analyzer. Please extend "org.apache.blur.analysis.type.CustomFieldTypeDefinition".
</p>
<p>
<h4>Example</h4>
Below is a simple type that is basically the same as a "string" type, however it's implemented by extending "org.apache.blur.analysis.type.CustomFieldTypeDefinition".<br/><br/>
<pre><code class="java">public class ExampleType extends CustomFieldTypeDefinition {
private String _fieldNameForThisInstance;
/**
* Get the name of the type.
*
* @return the name.
*/
@Override
public String getName() {
return "example";
}
/**
* Configures this instance for the type.
*
* @param fieldNameForThisInstance
* the field name for this instance.
* @param properties
* the properties passed into this type definition from the
* {@link Blur.Iface#addColumnDefinition(String, ColumnDefinition)}
* method.
*/
@Override
public void configure(String fieldNameForThisInstance, Map<String, String> properties,
Configuration configuration) {
_fieldNameForThisInstance = fieldNameForThisInstance;
}
/**
* Create {@link Field}s for the index as well as for storing the original
* data for retrieval.
*
* @param family
* the family name.
* @param column
* the column that holds the name and value.
*
* @return the {@link Iterable} of {@link Field}s.
*/
@Override
public Iterable&lt;? extends Field&gt; getFieldsForColumn(String family, Column column) {
String name = family + "." + column.getName();
String value = column.getValue();
return makeIterable(new StringField(name, value, Store.YES));
}
/**
* Create {@link Field}s for the index do NOT store the data because the is a
* sub column.
*
* @param family
* the family name.
* @param column
* the column that holds the name and value.
* @param subName
* the sub column name.
*
* @return the {@link Iterable} of {@link Field}s.
*/
@Override
public Iterable&lt;? extends Field&gt; getFieldsForSubColumn(String family, Column column,
String subName) {
String name = family + "." + column.getName() + "." + subName;
String value = column.getValue();
return makeIterable(new StringField(name, value, Store.NO));
}
/**
* Gets the query from the text provided by the query parser.
*
* @param text
* the text provided by the query parser.
* @return the {@link Query}.
*/
@Override
public Query getCustomQuery(String text) {
return new TermQuery(new Term(_fieldNameForThisInstance, text));
}
}
</code></pre>
</p>
<h3 id="custom_types_distributing">Distributing</h3>
<p>Once you have created and tested your custom type you will need to copy the jar file containing your custom type to all the servers in the cluster. The jar file will need to be located within the $BLUR_HOME/lib directory. Once there all the servers will need to be restarted to have the jar file be picked up in the classpath.<br/><br/>In a later version of Blur we hope to have this be a dynamic operation that can be performed without restarting the cluster.</p>
<h3 id="custom_types_using">Using</h3>
<p>You can either add your custom type to the entire cluster or per table.</p>
<h4 id="custom_types_using_cluster">Cluster Wide</h4>
<p>For cluster wide configuration you will need to add the new field types into the blur-site.properties file on each server.
<pre><code class="bash">blur.fieldtype.customtype1=org.apache.blur.analysis.type.ExampleType1
blur.fieldtype.customtype2=org.apache.blur.analysis.type.ExampleType2
...</code></pre>
Please note that the prefix of "blur.fieldtype." is all that is used from the property name because the type gets it's name from the internal method of "getName". However the property names will need to be unique within the file.
</p>
<h4 id="custom_types_using_table">Single Table</h4>
<p>For a single table configuration you will need to add the new field types into the tableProperties map in the TableDescriptor as you define the table.
<pre><code class="java">tableDescriptor.putToTableProperties("blur.fieldtype.customtype1",
"org.apache.blur.analysis.type.ExampleType1");
tableDescriptor.putToTableProperties("blur.fieldtype.customtype2",
"org.apache.blur.analysis.type.ExampleType2");
...</code></pre>
Please note that the prefix of "blur.fieldtype." is all that is used from the property name because the type gets it's name from the internal method of "getName". However the property names will need to be unique within the map.</p>
</section>
</div>
</div>
</div>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="resources/js/jquery-2.0.3.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="resources/js/bootstrap.min.js"></script>
<!-- Enable responsive features in IE8 with Respond.js (https://github.com/scottjehl/Respond) -->
<script src="resources/js/respond.min.js"></script>
<script src="resources/js/docs.js"></script>
</body>
</html>