Search in sources :

Example 1 with CopyField

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;
}
Also used : SchemaField(org.apache.solr.schema.SchemaField) SolrInputField(org.apache.solr.common.SolrInputField) Document(org.apache.lucene.document.Document) SolrInputDocument(org.apache.solr.common.SolrInputDocument) SolrException(org.apache.solr.common.SolrException) CopyField(org.apache.solr.schema.CopyField) SolrException(org.apache.solr.common.SolrException)

Example 2 with CopyField

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;
}
Also used : SchemaField(org.apache.solr.schema.SchemaField) SolrInputDocument(org.apache.solr.common.SolrInputDocument) IndexWriter(org.apache.lucene.index.IndexWriter) SolrCore(org.apache.solr.core.SolrCore) IndexSchema(org.apache.solr.schema.IndexSchema) Map(java.util.Map) CopyField(org.apache.solr.schema.CopyField) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Aggregations

SolrInputDocument (org.apache.solr.common.SolrInputDocument)2 CopyField (org.apache.solr.schema.CopyField)2 SchemaField (org.apache.solr.schema.SchemaField)2 HashSet (java.util.HashSet)1 LinkedHashSet (java.util.LinkedHashSet)1 Map (java.util.Map)1 Document (org.apache.lucene.document.Document)1 IndexWriter (org.apache.lucene.index.IndexWriter)1 SolrException (org.apache.solr.common.SolrException)1 SolrInputField (org.apache.solr.common.SolrInputField)1 SolrCore (org.apache.solr.core.SolrCore)1 IndexSchema (org.apache.solr.schema.IndexSchema)1