FieldType old = fieldTypes.put(ft.typeName,ft);
if( old != null ) {
String msg = "[schema.xml] Duplicate fieldType definition for '"
+ ft.typeName + "' ignoring: "+old.toString();
Throwable t = new SolrException( SolrException.ErrorCode.SERVER_ERROR, msg );
SolrException.logOnce(log,null,t);
SolrConfig.severeErrors.add( t );
}
log.finest("fieldtype defined: " + ft);
}
// Hang on to the fields that say if they are required -- this lets us set a reasonable default for the unique key
Map<String,Boolean> explicitRequiredProp = new HashMap<String, Boolean>();
ArrayList<DynamicField> dFields = new ArrayList<DynamicField>();
expression = "/schema/fields/field | /schema/fields/dynamicField";
nodes = (NodeList) xpath.evaluate(expression, document, XPathConstants.NODESET);
for (int i=0; i<nodes.getLength(); i++) {
Node node = nodes.item(i);
NamedNodeMap attrs = node.getAttributes();
String name = DOMUtil.getAttr(attrs,"name","field definition");
log.finest("reading field def "+name);
String type = DOMUtil.getAttr(attrs,"type","field " + name);
String val;
FieldType ft = fieldTypes.get(type);
if (ft==null) {
throw new SolrException( SolrException.ErrorCode.BAD_REQUEST,"Unknown fieldtype '" + type + "'",false);
}
Map<String,String> args = DOMUtil.toMapExcept(attrs, "name", "type");
if( args.get( "required" ) != null ) {
explicitRequiredProp.put( name, Boolean.valueOf( args.get( "required" ) ) );
}
SchemaField f = SchemaField.create(name,ft,args);
if (node.getNodeName().equals("field")) {
SchemaField old = fields.put(f.getName(),f);
if( old != null ) {
String msg = "[schema.xml] Duplicate field definition for '"
+ f.getName() + "' ignoring: "+old.toString();
Throwable t = new SolrException( SolrException.ErrorCode.SERVER_ERROR, msg );
SolrException.logOnce(log,null,t);
SolrConfig.severeErrors.add( t );
}
log.fine("field defined: " + f);
if( f.getDefaultValue() != null ) {
log.fine(name+" contains default value: " + f.getDefaultValue());
fieldsWithDefaultValue.add( f );
}
if (f.isRequired()) {
log.fine(name+" is required in this schema");
requiredFields.add(f);
}
} else if (node.getNodeName().equals("dynamicField")) {
// make sure nothing else has the same path
boolean dup = false;
for( DynamicField df : dFields ) {
if( df.regex.equals( f.name ) ) {
String msg = "[schema.xml] Duplicate DynamicField definition for '"
+ f.getName() + "' ignoring: "+f.toString();
Throwable t = new SolrException( SolrException.ErrorCode.SERVER_ERROR, msg );
SolrException.logOnce(log,null,t);
SolrConfig.severeErrors.add( t );
dup = true;
break;
}
}
if( !dup ) {
dFields.add(new DynamicField(f));
log.fine("dynamic field defined: " + f);
}
} else {
// we should never get here
throw new RuntimeException("Unknown field type");
}
}
//fields with default values are by definition required
//add them to required fields, and we only have to loop once
// in DocumentBuilder.getDoc()
requiredFields.addAll(getFieldsWithDefaultValue());
// OK, now sort the dynamic fields largest to smallest size so we don't get
// any false matches. We want to act like a compiler tool and try and match
// the largest string possible.
Collections.sort(dFields);
log.finest("Dynamic Field Ordering:" + dFields);
// stuff it in a normal array for faster access
dynamicFields = (DynamicField[])dFields.toArray(new DynamicField[dFields.size()]);
Node node = (Node) xpath.evaluate("/schema/similarity/@class", document, XPathConstants.NODE);
if (node==null) {
similarity = new DefaultSimilarity();
log.fine("using default similarity");
} else {
similarity = (Similarity)Config.newInstance(node.getNodeValue().trim());
log.fine("using similarity " + similarity.getClass().getName());
}
node = (Node) xpath.evaluate("/schema/defaultSearchField/text()", document, XPathConstants.NODE);
if (node==null) {
log.warning("no default search field specified in schema.");
} else {
defaultSearchFieldName=node.getNodeValue().trim();
// throw exception if specified, but not found or not indexed
if (defaultSearchFieldName!=null) getIndexedField(defaultSearchFieldName);
log.info("default search field is "+defaultSearchFieldName);
}
node = (Node) xpath.evaluate("/schema/solrQueryParser/@defaultOperator", document, XPathConstants.NODE);
if (node==null) {
log.fine("using default query parser operator (OR)");
} else {
queryParserDefaultOperator=node.getNodeValue().trim();
log.info("query parser default operator is "+queryParserDefaultOperator);
}
node = (Node) xpath.evaluate("/schema/uniqueKey/text()", document, XPathConstants.NODE);
if (node==null) {
log.warning("no uniqueKey specified in schema.");
} else {
uniqueKeyField=getIndexedField(node.getNodeValue().trim());
uniqueKeyFieldName=uniqueKeyField.getName();
uniqueKeyFieldType=uniqueKeyField.getType();
log.info("unique key field: "+uniqueKeyFieldName);
// Unless the uniqueKeyField is marked 'required=false' then make sure it exists
if( Boolean.FALSE != explicitRequiredProp.get( uniqueKeyFieldName ) ) {
uniqueKeyField.required = true;
requiredFields.add(uniqueKeyField);
}
}
/////////////// parse out copyField commands ///////////////
// Map<String,ArrayList<SchemaField>> cfields = new HashMap<String,ArrayList<SchemaField>>();
// expression = "/schema/copyField";
ArrayList<DynamicCopy> dCopies = new ArrayList<DynamicCopy>();
expression = "//copyField";
nodes = (NodeList) xpath.evaluate(expression, document, XPathConstants.NODESET);
for (int i=0; i<nodes.getLength(); i++) {
node = nodes.item(i);
NamedNodeMap attrs = node.getAttributes();
String source = DOMUtil.getAttr(attrs,"source","copyField definition");
String dest = DOMUtil.getAttr(attrs,"dest", "copyField definition");
boolean sourceIsPattern = isWildCard(source);
boolean destIsPattern = isWildCard(dest);
log.fine("copyField source='"+source+"' dest='"+dest+"'");
SchemaField d = getField(dest);
if(sourceIsPattern) {
if( destIsPattern ) {
DynamicField df = null;
for( DynamicField dd : dynamicFields ) {
if( dd.regex.equals( dest ) ) {
df = dd;
break;
}
}
if( df == null ) {
throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, "copyField dynamic destination must match a dynamicField." );
}
dCopies.add(new DynamicDestCopy(source, df ));
}
else {
dCopies.add(new DynamicCopy(source, d));
}
}
else if( destIsPattern ) {
String msg = "copyField only supports a dynamic destination if the source is also dynamic" ;
throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, msg );
}
else {
// retrieve the field to force an exception if it doesn't exist
SchemaField f = getField(source);
SchemaField[] destArr = copyFields.get(source);
if (destArr==null) {
destArr=new SchemaField[]{d};
} else {
destArr = (SchemaField[])append(destArr,d);
}
copyFields.put(source,destArr);
}
}
log.finest("Dynamic Copied Fields:" + dCopies);
// stuff it in a normal array for faster access
dynamicCopyFields = (DynamicCopy[])dCopies.toArray(new DynamicCopy[dCopies.size()]);
} catch (SolrException e) {
SolrConfig.severeErrors.add( e );
throw e;
} catch(Exception e) {
// unexpected exception...
SolrConfig.severeErrors.add( e );
throw new SolrException( SolrException.ErrorCode.SERVER_ERROR,"Schema Parsing Failed",e,false);
}
analyzer = new SolrIndexAnalyzer();
queryAnalyzer = new SolrQueryAnalyzer();
}