use of org.apache.solr.schema.CopyField in project lucene-solr by apache.
the class DocumentBuilder method toDocument.
/**
* Convert a SolrInputDocument to a lucene Document.
*
* This function should go elsewhere. This builds the Document without an
* extra Map<> checking for multiple values. For more discussion, see:
* http://www.nabble.com/Re%3A-svn-commit%3A-r547493---in--lucene-solr-trunk%3A-.--src-java-org-apache-solr-common--src-java-org-apache-solr-schema--src-java-org-apache-solr-update--src-test-org-apache-solr-common--tf3931539.html
*
* TODO: /!\ NOTE /!\ This semantics of this function are still in flux.
* Something somewhere needs to be able to fill up a SolrDocument from
* a lucene document - this is one place that may happen. It may also be
* moved to an independent function
*
* @since solr 1.3
*
* @param doc SolrInputDocument from which the document has to be built
* @param schema Schema instance
* @param forInPlaceUpdate Whether the output document would be used for an in-place update or not. When this is true,
* default fields values and copy fields targets are not populated.
* @return Built Lucene document
*/
public static Document toDocument(SolrInputDocument doc, IndexSchema schema, boolean forInPlaceUpdate) {
final SchemaField uniqueKeyField = schema.getUniqueKeyField();
final String uniqueKeyFieldName = null == uniqueKeyField ? null : uniqueKeyField.getName();
Document out = new Document();
Set<String> usedFields = Sets.newHashSet();
// Load fields from SolrDocument to Document
for (SolrInputField field : doc) {
String name = field.getName();
SchemaField sfield = schema.getFieldOrNull(name);
boolean used = false;
// Make sure it has the correct number
if (sfield != null && !sfield.multiValued() && field.getValueCount() > 1) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "ERROR: " + getID(doc, schema) + "multiple values encountered for non multiValued field " + sfield.getName() + ": " + field.getValue());
}
List<CopyField> copyFields = schema.getCopyFieldsList(name);
if (copyFields.size() == 0)
copyFields = null;
// load each field value
boolean hasField = false;
try {
for (Object v : field) {
if (v == null) {
continue;
}
hasField = true;
if (sfield != null) {
used = true;
addField(out, sfield, v, name.equals(uniqueKeyFieldName) ? false : forInPlaceUpdate);
// record the field as having a value
usedFields.add(sfield.getName());
}
// This could happen whether it is explicit or not.
if (copyFields != null) {
// and this is the uniqueKey field (because the uniqueKey can't change so no need to "update" the copyField).
if (!(forInPlaceUpdate && name.equals(uniqueKeyFieldName))) {
for (CopyField cf : copyFields) {
SchemaField destinationField = cf.getDestination();
final boolean destHasValues = usedFields.contains(destinationField.getName());
// check if the copy field is a multivalued or not
if (!destinationField.multiValued() && destHasValues) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "ERROR: " + getID(doc, schema) + "multiple values encountered for non multiValued copy field " + destinationField.getName() + ": " + v);
}
used = true;
// Perhaps trim the length of a copy field
Object val = v;
if (val instanceof String && cf.getMaxChars() > 0) {
val = cf.getLimitedValue((String) val);
}
addField(out, destinationField, val, destinationField.getName().equals(uniqueKeyFieldName) ? false : forInPlaceUpdate);
// record the field as having a value
usedFields.add(destinationField.getName());
}
}
}
}
} catch (SolrException ex) {
throw ex;
} catch (Exception ex) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "ERROR: " + getID(doc, schema) + "Error adding field '" + field.getName() + "'='" + field.getValue() + "' msg=" + ex.getMessage(), ex);
}
// make sure the field was used somehow...
if (!used && hasField) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "ERROR: " + getID(doc, schema) + "unknown field '" + name + "'");
}
}
// during the full indexing initially.
if (!forInPlaceUpdate) {
for (SchemaField field : schema.getRequiredFields()) {
if (out.getField(field.getName()) == null) {
if (field.getDefaultValue() != null) {
addField(out, field, field.getDefaultValue(), false);
} else {
String msg = getID(doc, schema) + "missing required field: " + field.getName();
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, msg);
}
}
}
}
if (!forInPlaceUpdate) {
moveLargestFieldLast(out);
}
return out;
}
use of org.apache.solr.schema.CopyField in project lucene-solr by apache.
the class AtomicUpdateDocumentMerger method computeInPlaceUpdatableFields.
/**
* Given an add update command, compute a list of fields that can be updated in-place. If there is even a single
* field in the update that cannot be updated in-place, the entire update cannot be executed in-place (and empty set
* will be returned in that case).
*
* @return Return a set of fields that can be in-place updated.
*/
public static Set<String> computeInPlaceUpdatableFields(AddUpdateCommand cmd) throws IOException {
SolrInputDocument sdoc = cmd.getSolrInputDocument();
IndexSchema schema = cmd.getReq().getSchema();
final SchemaField uniqueKeyField = schema.getUniqueKeyField();
final String uniqueKeyFieldName = null == uniqueKeyField ? null : uniqueKeyField.getName();
final Set<String> candidateFields = new HashSet<>();
// if _version_ field is not supported for in-place update, bail out early
SchemaField versionField = schema.getFieldOrNull(CommonParams.VERSION_FIELD);
if (versionField == null || !isSupportedFieldForInPlaceUpdate(versionField)) {
return Collections.emptySet();
}
// and bail out early if anything is obviously not a valid in-place update
for (String fieldName : sdoc.getFieldNames()) {
if (fieldName.equals(uniqueKeyFieldName) || fieldName.equals(CommonParams.VERSION_FIELD)) {
continue;
}
Object fieldValue = sdoc.getField(fieldName).getValue();
if (!(fieldValue instanceof Map)) {
// not an in-place update if there are fields that are not maps
return Collections.emptySet();
}
// else it's a atomic update map...
for (String op : ((Map<String, Object>) fieldValue).keySet()) {
if (!op.equals("set") && !op.equals("inc")) {
// not a supported in-place update op
return Collections.emptySet();
}
}
candidateFields.add(fieldName);
}
if (candidateFields.isEmpty()) {
return Collections.emptySet();
}
// this time more expensive checks involving schema/config settings
for (String fieldName : candidateFields) {
SchemaField schemaField = schema.getField(fieldName);
if (!isSupportedFieldForInPlaceUpdate(schemaField)) {
return Collections.emptySet();
}
// if this field has copy target which is not supported for in place, then empty
for (CopyField copyField : schema.getCopyFieldsList(fieldName)) {
if (!isSupportedFieldForInPlaceUpdate(copyField.getDestination()))
return Collections.emptySet();
}
}
// third pass: requiring checks against the actual IndexWriter due to internal DV update limitations
SolrCore core = cmd.getReq().getCore();
RefCounted<IndexWriter> holder = core.getSolrCoreState().getIndexWriter(core);
Set<String> fieldNamesFromIndexWriter = null;
Set<String> segmentSortingFields = null;
try {
IndexWriter iw = holder.get();
// This shouldn't be needed once LUCENE-7659 is resolved
fieldNamesFromIndexWriter = iw.getFieldNames();
segmentSortingFields = iw.getConfig().getIndexSortFields();
} finally {
holder.decref();
}
for (String fieldName : candidateFields) {
if (!fieldNamesFromIndexWriter.contains(fieldName)) {
// if this field doesn't exist, DV update can't work
return Collections.emptySet();
}
if (segmentSortingFields.contains(fieldName)) {
// if this is used for segment sorting, DV updates can't work
return Collections.emptySet();
}
}
return candidateFields;
}
Aggregations