001/* 002 * (C) Copyright 2014-2016 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo 018 */ 019 020package org.nuxeo.elasticsearch.config; 021 022import static org.nuxeo.elasticsearch.ElasticSearchConstants.ALL_FIELDS; 023import static org.nuxeo.elasticsearch.ElasticSearchConstants.BINARYTEXT_FIELD; 024import static org.nuxeo.elasticsearch.ElasticSearchConstants.DOC_TYPE; 025 026import org.nuxeo.common.xmap.annotation.XNode; 027import org.nuxeo.common.xmap.annotation.XNodeList; 028import org.nuxeo.common.xmap.annotation.XObject; 029 030/** 031 * XMap descriptor for configuring an index 032 * 033 * @author <a href="mailto:tdelprat@nuxeo.com">Tiry</a> 034 */ 035@XObject(value = "elasticSearchIndex") 036public class ElasticSearchIndexConfig { 037 038 @XNode("@enabled") 039 protected boolean isEnabled = true; 040 041 @Override 042 public String toString() { 043 if (isEnabled()) { 044 return String.format("EsIndexConfig(%s, %s, %s)", getName(), getRepositoryName(), getType()); 045 } 046 return "EsIndexConfig disabled"; 047 } 048 049 @XNode("@name") 050 protected String name; 051 052 @XNode("@repository") 053 protected String repositoryName; 054 055 private static final String DEFAULT_REPOSITORY_NAME = "default"; 056 057 @XNode("@type") 058 protected String type = DOC_TYPE; 059 060 @XNode("@create") 061 protected boolean create = true; 062 063 @XNode("settings") 064 protected String settings; 065 066 final public static String DEFAULT_SETTING = "{\n" // 067 + " \"number_of_shards\" : 1,\n" // 068 + " \"number_of_replicas\" : 0,\n" // 069 + " \"analysis\" : {\n" // 070 + " \"filter\" : {\n" // 071 + " \"truncate_filter\" : {\n" // 072 + " \"length\" : 256,\n" // 073 + " \"type\" : \"truncate\"\n" // 074 + " },\n" // 075 + " \"en_stem_filter\" : {\n" // 076 + " \"name\" : \"minimal_english\",\n" // 077 + " \"type\" : \"stemmer\"\n" // 078 + " },\n" // 079 + " \"en_stop_filter\" : {\n" // 080 + " \"stopwords\" : [\n" // 081 + " \"_english_\"\n" // 082 + " ],\n" // 083 + " \"type\" : \"stop\"\n" // 084 + " }\n" // 085 + " },\n" // 086 + " \"tokenizer\" : {\n" // 087 + " \"path_tokenizer\" : {\n" // 088 + " \"delimiter\" : \"/\",\n" // 089 + " \"type\" : \"path_hierarchy\"\n" // 090 + " }\n" + " },\n" // 091 + " \"analyzer\" : {\n" // 092 + " \"en_analyzer\" : {\n" // 093 + " \"alias\" : \"fulltext\",\n" // 094 + " \"filter\" : [\n" // 095 + " \"lowercase\",\n" // 096 + " \"en_stop_filter\",\n" // 097 + " \"en_stem_filter\",\n" // 098 + " \"asciifolding\"\n" // 099 + " ],\n" // 100 + " \"type\" : \"custom\",\n" // 101 + " \"tokenizer\" : \"standard\"\n" // 102 + " },\n" // 103 + " \"path_analyzer\" : {\n" // 104 + " \"type\" : \"custom\",\n" // 105 + " \"tokenizer\" : \"path_tokenizer\"\n" // 106 + " },\n" // 107 + " \"default\" : {\n" // 108 + " \"type\" : \"custom\",\n" // 109 + " \"tokenizer\" : \"keyword\",\n" // 110 + " \"filter\" : [\n" // 111 + " \"truncate_filter\"\n" // 112 + " ]\n" // 113 + " }\n" // 114 + " }\n" // 115 + " }\n" // 116 + "}"; 117 118 @XNode("mapping") 119 protected String mapping; 120 121 final public static String DEFAULT_MAPPING = "{\n" // 122 + " \"_all\" : {\n" // 123 + " \"analyzer\" : \"fulltext\"\n" // 124 + " },\n" // 125 + " \"properties\" : {\n" // 126 + " \"dc:title\" : {\n" // 127 + " \"type\" : \"multi_field\",\n" // 128 + " \"fields\" : {\n" // 129 + " \"dc:title\" : {\n" // 130 + " \"type\" : \"string\"\n" // 131 + " },\n" // 132 + " \"fulltext\" : {\n" // 133 + " \"boost\": 2,\n" // 134 + " \"type\": \"string\",\n" // 135 + " \"analyzer\" : \"fulltext\"\n" // 136 + " }\n" // 137 + " }\n" // 138 + " },\n" // 139 + " \"dc:description\" : {\n" // 140 + " \"type\" : \"multi_field\",\n" // 141 + " \"fields\" : {\n" // 142 + " \"dc:description\" : {\n" // 143 + " \"type\" : \"string\"\n" // 144 + " },\n" // 145 + " \"fulltext\" : {\n" // 146 + " \"boost\": 1.5,\n" // 147 + " \"type\": \"string\",\n" // 148 + " \"analyzer\" : \"fulltext\"\n" // 149 + " }\n" // 150 + " }\n" // 151 + " },\n" // 152 + " \"ecm:binarytext\" : {\n" // 153 + " \"type\" : \"string\",\n" // 154 + " \"index\" : \"no\",\n" // 155 + " \"include_in_all\" : true\n" // 156 + " },\n" // 157 + " \"ecm:path\" : {\n" // 158 + " \"type\" : \"multi_field\",\n" // 159 + " \"fields\" : {\n" // 160 + " \"children\" : {\n" // 161 + " \"analyzer\" : \"path_analyzer\",\n" // 162 + " \"search_analyzer\" : \"keyword\",\n" // 163 + " \"type\" : \"string\"\n" // 164 + " },\n" // 165 + " \"ecm:path\" : {\n" // 166 + " \"index\" : \"not_analyzed\",\n" // 167 + " \"type\" : \"string\"\n" // 168 + " }\n" // 169 + " }\n" // 170 + " },\n" // 171 + " \"dc:created\": {\n" // 172 + " \"format\": \"dateOptionalTime\",\n" // 173 + " \"type\": \"date\"\n" // 174 + " },\n" // 175 + " \"dc:modified\": {\n" // 176 + " \"format\": \"dateOptionalTime\",\n" // 177 + " \"type\": \"date\"\n" // 178 + " },\n" // 179 + " \"ecm:pos*\" : {\n" // 180 + " \"type\" : \"integer\"\n" // 181 + " }\n" // 182 + " }\n" // 183 + "}"; 184 185 @XNodeList(value = "fetchFromSource/exclude", type = String[].class, componentType = String.class) 186 protected String[] excludes; 187 188 @XNodeList(value = "fetchFromSource/include", type = String[].class, componentType = String.class) 189 protected String[] includes; 190 191 public String[] getExcludes() { 192 if (excludes == null) { 193 return new String[] { BINARYTEXT_FIELD }; 194 } 195 return excludes; 196 } 197 198 public String[] getIncludes() { 199 if (includes == null || includes.length == 0) { 200 return new String[] { ALL_FIELDS }; 201 } 202 return includes; 203 } 204 205 public String getName() { 206 return name; 207 } 208 209 public String getType() { 210 return type; 211 } 212 213 public String getSettings() { 214 return settings == null ? DEFAULT_SETTING : settings; 215 } 216 217 public String getMapping() { 218 return mapping == null ? DEFAULT_MAPPING : mapping; 219 } 220 221 public boolean mustCreate() { 222 return create; 223 } 224 225 public String getRepositoryName() { 226 if (isDocumentIndex() && repositoryName == null) { 227 repositoryName = DEFAULT_REPOSITORY_NAME; 228 } 229 return repositoryName; 230 } 231 232 public boolean isEnabled() { 233 return isEnabled; 234 } 235 236 public void setEnabled(boolean isEnabled) { 237 this.isEnabled = isEnabled; 238 } 239 240 /** 241 * Return true if the index/mapping is associated with a Nuxeo document repository 242 * 243 * @since 7.4 244 */ 245 public boolean isDocumentIndex() { 246 return DOC_TYPE.equals(getType()); 247 } 248 249 /** 250 * Use {@code other} mapping and settings if not defined. 251 */ 252 public void merge(final ElasticSearchIndexConfig other) { 253 if (other == null) { 254 return; 255 } 256 if (mapping == null && other.mapping != null) { 257 mapping = other.mapping; 258 } 259 if (settings == null && other.settings != null) { 260 settings = other.settings; 261 } 262 } 263 264}