package com.lucidworks.storm.solr;
import org.apache.solr.common.SolrInputDocument;
import java.util.List;
import java.util.Map;
/**
* Take a Map and transform it into a SolrInputDocument by flattening nested fields into a single document; for
* block-join style nested documents, see NestedDocumentMapper
*/
public class JsonDocumentMapper implements SolrInputDocumentMapper {
protected String idFieldName = "id";
protected String compoundNameDelimiter = ".";
public String getIdFieldName() {
return idFieldName;
}
public void setIdFieldName(String idFieldName) {
this.idFieldName = idFieldName;
}
public String getCompoundNameDelimiter() {
return compoundNameDelimiter;
}
public void setCompoundNameDelimiter(String compoundNameDelimiter) {
this.compoundNameDelimiter = compoundNameDelimiter;
}
public SolrInputDocument toInputDoc(String docId, Object obj) {
SolrInputDocument doc = new SolrInputDocument();
doc.setField(idFieldName, docId);
addFieldsToDoc(null /* top level no prefix */, doc, (Map)obj);
return doc;
}
protected void addFieldsToDoc(String prefix, SolrInputDocument doc, Map map) {
for (Object key : map.keySet()) {
Object val = map.get(key);
if (val != null)
addFieldToDoc(prefix, doc, key.toString(), val);
}
}
protected void addFieldToDoc(String prefix, SolrInputDocument doc, String fieldName, Object fieldValue) {
if (fieldValue instanceof List) {
// peek in the list to see if the values are flat or nested objects
List list = (List)fieldValue;
if (list.isEmpty())
return;
Object first = list.get(0);
if (first instanceof Map) {
// nested object here
String fieldNamePrefix = fname(prefix, fieldName);
for (int i=0; i < list.size(); i++) {
addFieldsToDoc(fname(fieldNamePrefix,i), doc, (Map)list.get(i));
}
} else if (first instanceof List) {
// list of list
String fieldNamePrefix = fname(prefix, fieldName);
for (int i=0; i < list.size(); i++) {
addFieldToDoc(fieldNamePrefix, doc, String.valueOf(i), (List)list.get(i));
}
} else {
// just a multi-valued field here
doc.setField(fname(prefix, fieldName), fieldValue);
}
} else if (fieldValue instanceof Map) {
addFieldsToDoc(fname(prefix, fieldName), doc, (Map)fieldValue);
} else {
// default behavior, just add this field to the doc
doc.setField(fname(prefix, fieldName), fieldValue);
}
}
protected final String fname(final String prefix, final String name) {
return (prefix != null) ? prefix + compoundNameDelimiter + name : name;
}
protected final String fname(final String prefix, final int index) {
return prefix + compoundNameDelimiter + index;
}
}