org.apache.solr.update.processor.FieldMutatingUpdateProcessorFactory Maven / Gradle / Ivy
Show all versions of solr-core Show documentation
/*
* 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.
*/
package org.apache.solr.update.processor;
import static org.apache.solr.update.processor.FieldMutatingUpdateProcessor.SELECT_ALL_FIELDS;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.SolrCore;
import org.apache.solr.update.processor.FieldMutatingUpdateProcessor.FieldNameSelector;
import org.apache.solr.util.plugin.SolrCoreAware;
/**
* Base class for implementing Factories for FieldMutatingUpdateProcessors and
* FieldValueMutatingUpdateProcessors.
*
* This class provides all of the plumbing for configuring the FieldNameSelector using the
* following init params to specify selection criteria...
*
*
* fieldName
- selecting specific fields by field name lookup
* fieldRegex
- selecting specific fields by field name regex match (regexes are
* checked in the order specified)
* typeName
- selecting specific fields by fieldType name lookup
* typeClass
- selecting specific fields by fieldType class lookup, including
* inheritence and interfaces
*
*
* Each criteria can specified as either an <arr> of <str>, or multiple <str>
* with the same name. When multiple criteria of a single type exist, fields must match at least
* one to be selected. If more then one type of criteria exist, fields must match at least
* one of each to be selected.
*
*
The following additional selector may be specified as a <bool> - when specified as
* false, only fields that do not match a schema field/dynamic field are selected; when
* specified as true, only fields that do match a schema field/dynamic field are selected:
*
*
* fieldNameMatchesSchemaField
- selecting specific fields based on whether or
* not they match a schema field
*
*
* One or more excludes
<lst> params may also be specified, containing any of
* the above criteria, identifying fields to be excluded from seelction even if they match the
* selection criteria. As with the main selection critiera a field must match all of criteria in a
* single exclusion in order to be excluded, but multiple exclusions may be specified to get an
* OR
behavior
*
*
In the ExampleFieldMutatingUpdateProcessorFactory configured below, fields will be mutated if
* the name starts with "foo" or "bar"; unless the field name contains the substring
* "SKIP" or the fieldType is (or subclasses) DatePointField. Meaning a field named
* "foo_SKIP" is guaranteed not to be selected, but a field named "bar_smith" that uses StrField
* will be selected.
*
*
* <processor class="solr.ExampleFieldMutatingUpdateProcessorFactory">
* <str name="fieldRegex">foo.*</str>
* <str name="fieldRegex">bar.*</str>
* <!-- each set of exclusions is checked independently -->
* <lst name="exclude">
* <str name="fieldRegex">.*SKIP.*</str>
* </lst>
* <lst name="exclude">
* <str name="typeClass">solr.DatePointField</str>
* </lst>
* </processor>
*
* Subclasses define the default selection behavior to be applied if no criteria is configured by
* the user. User configured "exclude" criteria will be applied to the subclass defined default
* selector.
*
* @see FieldMutatingUpdateProcessor
* @see FieldValueMutatingUpdateProcessor
* @see FieldNameSelector
* @since 4.0.0
*/
public abstract class FieldMutatingUpdateProcessorFactory extends UpdateRequestProcessorFactory
implements SolrCoreAware {
public static final class SelectorParams {
public Set fieldName = Collections.emptySet();
public Set typeName = Collections.emptySet();
public Collection typeClass = Collections.emptyList();
public Collection fieldRegex = Collections.emptyList();
public Boolean fieldNameMatchesSchemaField = null; // null => not specified
public boolean noSelectorsSpecified() {
return typeClass.isEmpty()
&& typeName.isEmpty()
&& fieldRegex.isEmpty()
&& fieldName.isEmpty()
&& null == fieldNameMatchesSchemaField;
}
}
private SelectorParams inclusions = new SelectorParams();
private Collection exclusions = new ArrayList<>();
private FieldNameSelector selector = null;
protected final FieldNameSelector getSelector() {
if (null != selector) return selector;
throw new SolrException(
SolrException.ErrorCode.SERVER_ERROR,
"selector was never initialized, inform(SolrCore) never called???");
}
public static SelectorParams parseSelectorParams(NamedList args) {
SelectorParams params = new SelectorParams();
params.fieldName = new HashSet<>(args.removeConfigArgs("fieldName"));
params.typeName = new HashSet<>(args.removeConfigArgs("typeName"));
// we can compile the patterns now
Collection patterns = args.removeConfigArgs("fieldRegex");
if (!patterns.isEmpty()) {
params.fieldRegex = new ArrayList<>(patterns.size());
for (String s : patterns) {
try {
params.fieldRegex.add(Pattern.compile(s));
} catch (PatternSyntaxException e) {
throw new SolrException(
SolrException.ErrorCode.SERVER_ERROR, "Invalid 'fieldRegex' pattern: " + s, e);
}
}
}
// resolve this into actual Class objects later
params.typeClass = args.removeConfigArgs("typeClass");
// Returns null if the arg is not specified
params.fieldNameMatchesSchemaField = args.removeBooleanArg("fieldNameMatchesSchemaField");
return params;
}
public static Collection parseSelectorExclusionParams(NamedList args) {
Collection exclusions = new ArrayList<>();
List excList = args.getAll("exclude");
for (Object excObj : excList) {
if (null == excObj) {
throw new SolrException(
SolrException.ErrorCode.SERVER_ERROR, "'exclude' init param can not be null");
}
if (!(excObj instanceof NamedList)) {
throw new SolrException(
SolrException.ErrorCode.SERVER_ERROR, "'exclude' init param must be ");
}
NamedList exc = (NamedList) excObj;
exclusions.add(parseSelectorParams(exc));
if (0 < exc.size()) {
throw new SolrException(
SolrException.ErrorCode.SERVER_ERROR,
"Unexpected 'exclude' init sub-param(s): '" + args.getName(0) + "'");
}
// call once per instance
args.remove("exclude");
}
return exclusions;
}
/**
* Handles common initialization related to source fields for constructing the FieldNameSelector
* to be used.
*
* Will error if any unexpected init args are found, so subclasses should remove any
* subclass-specific init args before calling this method.
*/
@Override
public void init(NamedList args) {
inclusions = parseSelectorParams(args);
exclusions = parseSelectorExclusionParams(args);
if (0 < args.size()) {
throw new SolrException(
SolrException.ErrorCode.SERVER_ERROR,
"Unexpected init param(s): '" + args.getName(0) + "'");
}
}
@Override
public void inform(final SolrCore core) {
selector =
FieldMutatingUpdateProcessor.createFieldNameSelector(
core.getResourceLoader(), core, inclusions, getDefaultSelector(core));
for (SelectorParams exc : exclusions) {
selector =
FieldMutatingUpdateProcessor.wrap(
selector,
FieldMutatingUpdateProcessor.createFieldNameSelector(
core.getResourceLoader(),
core,
exc,
FieldMutatingUpdateProcessor.SELECT_NO_FIELDS));
}
}
/**
* Defines the default selection behavior when the user has not configured any specific criteria
* for selecting fields. The Default implementation matches all fields, and should be overridden
* by subclasses as needed.
*
* @see FieldMutatingUpdateProcessor#SELECT_ALL_FIELDS
*/
protected FieldNameSelector getDefaultSelector(SolrCore core) {
return SELECT_ALL_FIELDS;
}
}