org.apache.solr.common.SolrDocument.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.solr.common.SolrDocument.java

Source

/*
 * 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.common;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.solr.common.util.NamedList;

/**
 * A concrete representation of a document within a Solr index.  Unlike a lucene
 * Document, a SolrDocument may have an Object value matching the type defined in
 * schema.xml
 * 
 * For indexing documents, use the SolrInputDocument that contains extra information
 * for document and field boosting.
 * 
 *
 * @since solr 1.3
 */
public class SolrDocument extends SolrDocumentBase<Object, SolrDocument>
        implements Iterable<Map.Entry<String, Object>> {
    protected final Map<String, Object> _fields;

    private List<SolrDocument> _childDocuments;

    public SolrDocument() {
        _fields = new LinkedHashMap<>();
    }

    @Override
    public void writeMap(EntryWriter ew) throws IOException {
        _fields.forEach(ew.getBiConsumer());
    }

    public SolrDocument(Map<String, Object> fields) {
        this._fields = fields;
    }

    /**
     * @return a list of field names defined in this document - this Collection is directly backed by this SolrDocument.
     * @see #keySet
     */
    @Override
    public Collection<String> getFieldNames() {
        return this.keySet();
    }

    ///////////////////////////////////////////////////////////////////
    // Add / Set / Remove Fields
    ///////////////////////////////////////////////////////////////////

    /**
     * Remove all fields from the document
     */
    @Override
    public void clear() {
        _fields.clear();

        if (_childDocuments != null) {
            _childDocuments.clear();
        }
    }

    /**
     * Remove all fields with the name
     */
    public boolean removeFields(String name) {
        return this.remove(name) != null;
    }

    /**
     * Set a field with the given object.  If the object is an Array, it will 
     * set multiple fields with the included contents.  This will replace any existing 
     * field with the given name
     */
    @SuppressWarnings("unchecked")
    public void setField(String name, Object value) {
        if (value instanceof Object[]) {
            value = new ArrayList(Arrays.asList((Object[]) value));
        } else if (value instanceof Collection) {
            // nothing
        } else if (value instanceof NamedList) {
            // nothing
        } else if (value instanceof Iterable && !(value instanceof SolrDocumentBase)) {
            ArrayList<Object> lst = new ArrayList<>();
            for (Object o : (Iterable) value) {
                lst.add(o);
            }
            value = lst;
        }
        _fields.put(name, value);
    }

    /**
     * This will add a field to the document.  If fields already exist with this
     * name it will append value to the collection. If the value is Collection,
     * each value will be added independently. 
     * 
     * The class type of value and the name parameter should match schema.xml. 
     * schema.xml can be found in conf directory under the solr home by default.
     * 
     * @param name Name of the field, should match one of the field names defined under "fields" tag in schema.xml.
     * @param value Value of the field, should be of same class type as defined by "type" attribute of the corresponding field in schema.xml. 
     */
    @SuppressWarnings("unchecked")
    @Override
    public void addField(String name, Object value) {
        Object existing = _fields.get(name);
        if (existing == null) {
            if (value instanceof Collection) {
                Collection<Object> c = new ArrayList<>(3);
                for (Object o : (Collection<Object>) value) {
                    c.add(o);
                }
                this.setField(name, c);
            } else {
                this.setField(name, value);
            }
            return;
        }

        Collection<Object> vals = null;
        if (existing instanceof Collection) {
            vals = (Collection<Object>) existing;
        } else {
            vals = new ArrayList<>(3);
            vals.add(existing);
        }

        // Add the values to the collection
        if (value instanceof Iterable && !(value instanceof SolrDocumentBase)) {
            for (Object o : (Iterable<Object>) value) {
                vals.add(o);
            }
        } else if (value instanceof Object[]) {
            for (Object o : (Object[]) value) {
                vals.add(o);
            }
        } else {
            vals.add(value);
        }
        _fields.put(name, vals);
    }

    ///////////////////////////////////////////////////////////////////
    // Get the field values
    ///////////////////////////////////////////////////////////////////

    /**
     * returns the first value for a field
     */
    public Object getFirstValue(String name) {
        Object v = _fields.get(name);
        if (v == null || !(v instanceof Collection))
            return v;
        Collection c = (Collection) v;
        if (c.size() > 0) {
            return c.iterator().next();
        }
        return null;
    }

    /**
     * Get the value or collection of values for a given field.  
     */
    @Override
    public Object getFieldValue(String name) {
        return _fields.get(name);
    }

    /**
     * Get a collection of values for a given field name
     */
    @SuppressWarnings("unchecked")
    @Override
    public Collection<Object> getFieldValues(String name) {
        Object v = _fields.get(name);
        if (v instanceof Collection) {
            return (Collection<Object>) v;
        }
        if (v != null) {
            ArrayList<Object> arr = new ArrayList<>(1);
            arr.add(v);
            return arr;
        }
        return null;
    }

    @Override
    public String toString() {
        return "SolrDocument" + _fields;
    }

    /**
     * Iterate of String-&gt;Object keys
     */
    @Override
    public Iterator<Entry<String, Object>> iterator() {
        return _fields.entrySet().iterator();
    }

    //-----------------------------------------------------------------------------------------
    // JSTL Helpers
    //-----------------------------------------------------------------------------------------

    /**
     * Expose a Map interface to the solr field value collection.
     */
    public Map<String, Collection<Object>> getFieldValuesMap() {
        return new Map<String, Collection<Object>>() {
            /** Get the field Value */
            @Override
            public Collection<Object> get(Object key) {
                return getFieldValues((String) key);
            }

            // Easily Supported methods
            @Override
            public boolean containsKey(Object key) {
                return _fields.containsKey(key);
            }

            @Override
            public Set<String> keySet() {
                return _fields.keySet();
            }

            @Override
            public int size() {
                return _fields.size();
            }

            @Override
            public boolean isEmpty() {
                return _fields.isEmpty();
            }

            // Unsupported operations.  These are not necessary for JSTL
            @Override
            public void clear() {
                throw new UnsupportedOperationException();
            }

            @Override
            public boolean containsValue(Object value) {
                throw new UnsupportedOperationException();
            }

            @Override
            public Set<java.util.Map.Entry<String, Collection<Object>>> entrySet() {
                throw new UnsupportedOperationException();
            }

            @Override
            public void putAll(Map<? extends String, ? extends Collection<Object>> t) {
                throw new UnsupportedOperationException();
            }

            @Override
            public Collection<Collection<Object>> values() {
                throw new UnsupportedOperationException();
            }

            @Override
            public Collection<Object> put(String key, Collection<Object> value) {
                throw new UnsupportedOperationException();
            }

            @Override
            public Collection<Object> remove(Object key) {
                throw new UnsupportedOperationException();
            }

            @Override
            public String toString() {
                return _fields.toString();
            }
        };
    }

    /**
     * Expose a Map interface to the solr fields.  This function is useful for JSTL
     */
    public Map<String, Object> getFieldValueMap() {
        return new Map<String, Object>() {
            /** Get the field Value */
            @Override
            public Object get(Object key) {
                return getFirstValue((String) key);
            }

            // Easily Supported methods
            @Override
            public boolean containsKey(Object key) {
                return _fields.containsKey(key);
            }

            @Override
            public Set<String> keySet() {
                return _fields.keySet();
            }

            @Override
            public int size() {
                return _fields.size();
            }

            @Override
            public boolean isEmpty() {
                return _fields.isEmpty();
            }

            // Unsupported operations.  These are not necessary for JSTL
            @Override
            public void clear() {
                throw new UnsupportedOperationException();
            }

            @Override
            public boolean containsValue(Object value) {
                throw new UnsupportedOperationException();
            }

            @Override
            public Set<java.util.Map.Entry<String, Object>> entrySet() {
                throw new UnsupportedOperationException();
            }

            @Override
            public void putAll(Map<? extends String, ? extends Object> t) {
                throw new UnsupportedOperationException();
            }

            @Override
            public Collection<Object> values() {
                throw new UnsupportedOperationException();
            }

            @Override
            public Collection<Object> put(String key, Object value) {
                throw new UnsupportedOperationException();
            }

            @Override
            public Collection<Object> remove(Object key) {
                throw new UnsupportedOperationException();
            }

            @Override
            public String toString() {
                return _fields.toString();
            }
        };
    }

    //---------------------------------------------------
    // MAP interface
    //---------------------------------------------------

    @Override
    public boolean containsKey(Object key) {
        return _fields.containsKey(key);
    }

    @Override
    public boolean containsValue(Object value) {
        return _fields.containsValue(value);
    }

    @Override
    public Set<Entry<String, Object>> entrySet() {
        return _fields.entrySet();
    }

    //TODO: Shouldn't the input parameter here be a String?  The _fields map requires a String.
    @Override
    public Object get(Object key) {
        return _fields.get(key);
    }

    @Override
    public boolean isEmpty() {
        return _fields.isEmpty();
    }

    @Override
    public Set<String> keySet() {
        return _fields.keySet();
    }

    @Override
    public Object put(String key, Object value) {
        return _fields.put(key, value);
    }

    @Override
    public void putAll(Map<? extends String, ? extends Object> t) {
        _fields.putAll(t);
    }

    @Override
    public Object remove(Object key) {
        return _fields.remove(key);
    }

    @Override
    public int size() {
        return _fields.size();
    }

    @Override
    public Collection<Object> values() {
        return _fields.values();
    }

    @Override
    public void addChildDocument(SolrDocument child) {
        if (_childDocuments == null) {
            _childDocuments = new ArrayList<>();
        }
        _childDocuments.add(child);
    }

    @Override
    public void addChildDocuments(Collection<SolrDocument> children) {
        for (SolrDocument child : children) {
            addChildDocument(child);
        }
    }

    @Override
    public List<SolrDocument> getChildDocuments() {
        return _childDocuments;
    }

    @Override
    public boolean hasChildDocuments() {
        boolean isEmpty = (_childDocuments == null || _childDocuments.isEmpty());
        return !isEmpty;
    }

    @Override
    public int getChildDocumentCount() {
        if (_childDocuments == null)
            return 0;
        return _childDocuments.size();
    }
}