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