2 * Copyright 2010-2013 Ben Birch
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this software except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 notes on elasticsearch terminology used in this project
21 indices[index] contains one or more
22 types[type] contains one or more
23 documents contain one or more
25 each path contains one element of data
26 each path maps to one field
28 eg PUT, "/twitter/tweet/1"
32 message: "You know, for browsing elasticsearch",
41 this is the collection of index data
43 this is the type of document (kind of like a table in sql)
44 1 document: /twitter/tweet/1
45 this is an actual document in the index ( kind of like a row in sql)
46 5 paths: [ ["user"], ["date"], ["message"], ["name","first"], ["name","last"] ]
47 since documents can be heirarchical this maps a path from a document root to a piece of data
48 5 fields: [ "user", "date", "message", "first", "last" ]
49 this is an indexed 'column' of data. fields are not heirarchical
51 the relationship between a path and a field is called a mapping. mappings also contain a wealth of information about how es indexes the field
54 1) a path is stored as an array, the dpath is <index> . <type> . path.join("."),
55 which can be considered the canonical reference for a mapping
56 2) confusingly, es uses the term index for both the collection of indexed data, and the individually indexed fields
57 so the term index_name is the same as field_name in this sense.
61 var data = app.ns("data");
62 var ux = app.ns("ux");
76 "boolean" : "boolean",
78 "multi_field" : "multi_field"
81 var default_property_map = {
82 "string" : { "store" : "no", "index" : "analysed" },
83 "number" : { "store" : "no", "precision_steps" : 4 },
84 "date" : { "store" : "no", "format" : "dateOptionalTime", "index": "yes", "precision_steps": 4 },
85 "boolean" : { "store" : "no", "index": "yes" },
90 // parses metatdata from a cluster, into a bunch of useful data structures
91 data.MetaData = ux.Observable.extend({
93 state: null // (required) response from a /_cluster/state request
97 this.refresh(this.config.state);
99 getIndices: function(alias) {
100 return alias ? this.aliases[alias] : this.indicesList;
102 // returns an array of strings containing all types that are in all of the indices passed in, or all types
103 getTypes: function(indices) {
104 var indices = indices || [], types = [];
105 this.typesList.forEach(function(type) {
106 for(var i = 0; i < indices.length; i++) {
107 if(! this.indices[indices[i]].types.contains(type))
114 refresh: function(state) {
115 // currently metadata expects all like named fields to have the same type, even when from different types and indices
116 var aliases = this.aliases = {};
117 var indices = this.indices = {};
118 var types = this.types = {};
119 var fields = this.fields = {};
120 var paths = this.paths = {};
122 function createField( mapping, index, type, path, name ) {
123 var dpath = [ index, type ].concat( path ).join( "." );
124 var field_name = mapping.index_name || path.join( "." );
125 var field = paths[ dpath ] = fields[ field_name ] || $.extend({
126 field_name : field_name,
127 core_type : coretype_map[ mapping.type ],
129 }, default_property_map[ coretype_map[ mapping.type ] ], mapping );
131 if (field.type === "multi_field" && typeof field.fields !== "undefined") {
132 for (var subField in field.fields) {
133 field.fields[ subField ] = createField( field.fields[ subField ], index, type, path.concat( subField ), name + "." + subField );
137 field.dpaths.push(dpath);
141 function getFields(properties, type, index, listeners) {
142 (function procPath(prop, path) {
143 for (var n in prop) {
144 if ("properties" in prop[n]) {
145 procPath( prop[ n ].properties, path.concat( n ) );
147 var field = createField(prop[n], index, type, path.concat(n), n);
148 listeners.forEach( function( listener ) {
149 listener[ field.field_name ] = field;
155 for (var index in state.metadata.indices) {
157 types : [], fields : {}, paths : {}, parents : {}
159 indices[index].aliases = state.metadata.indices[index].aliases;
160 indices[index].aliases.forEach(function(alias) {
161 (aliases[alias] || (aliases[alias] = [])).push(index);
163 var mapping = state.metadata.indices[index].mappings;
164 for (var type in mapping) {
165 indices[index].types.push(type);
166 if ( type in types) {
167 types[type].indices.push(index);
170 indices : [index], fields : {}
173 getFields(mapping[type].properties, type, index, [fields, types[type].fields, indices[index].fields]);
174 if ( typeof mapping[type]._parent !== "undefined") {
175 indices[index].parents[type] = mapping[type]._parent.type;
180 this.aliasesList = Object.keys(aliases);
181 this.indicesList = Object.keys(indices);
182 this.typesList = Object.keys(types);
183 this.fieldsList = Object.keys(fields);