Previously, I blogged about connecting Redis to Solr for relevance boosting via a custom FunctionQuery. Now, I'll talk about doing the same with MongoDB.

In solrconfig.xml, declare your ValueSourceParser.

<valueSourceParser name="mongo" class="org.supermind.solr.mongodb.MongoDBValueSourceParser">
  <str name="host">localhost</str>
  <str name="dbName">solr</str>
  <str name="collectionName">electronics</str>
  <str name="key">userId</str>
  <str name="idField">id</str>
</valueSourceParser>
 

The host, dbName and collectionName parameters are self-explanatory.

The key parameter is used to specify how to match for a MongoDB doc. The idField parameter declares the Solr field used for matching.

Here's the ValueSourceParser.

public class MongoDBValueSourceParser extends ValueSourceParser {

  private String idField;
  private String dbName;
  private String collectionName;
  private String key;
  private String host;
  private DBCollection collection;

  @Override public void init(NamedList args) {
    host = (String) args.get("host");
    idField = (String) args.get("idField");
    dbName = (String) args.get("dbName");
    collectionName = (String) args.get("collectionName");
    key = (String) args.get("key");
    try {
      Mongo mongo = new Mongo(host);
      collection = mongo.getDB(dbName).getCollection(collectionName);
    } catch (UnknownHostException e) {
      throw new IllegalArgumentException(e);
    }
  }

  @Override public ValueSource parse(FunctionQParser fp) throws ParseException {
    String value = fp.parseArg();

    final DBObject obj = collection.findOne(new BasicDBObject(key, value));
    return new MongoDBValueSource(idField, obj, value);
  }
}
 

Here's the interesting method in MongoDBValueSource.

  @Override public DocValues getValues(Map context, IndexReader reader) throws IOException {
    final String[] lookup = FieldCache.DEFAULT.getStrings(reader, idField);
    return new DocValues() {
      @Override public byte byteVal(int doc) {
        return (byte) intVal(doc);
      }

      @Override public short shortVal(int doc) {
        return (short) intVal(doc);
      }

      @Override public float floatVal(int doc) {
        final String id = lookup[doc];
        if (obj == null) return 0;
        Object v = obj.get(id);
        if (v == null) return 0;
        if (v instanceof Float) {
          return ((Float) v);
        } else if (v instanceof Integer) {
          return ((Integer) v);
        } else if (v instanceof String) {
          try {
            return Float.parseFloat((String) v);
          } catch (NumberFormatException e) {
            return 0;
          }
        }
        return 0;
      }

      @Override public int intVal(int doc) {
        final String id = lookup[doc];
        if (obj == null) return 0;
        Object v = obj.get(id);
        if (v == null) return 0;
        if (v instanceof Integer) {
          return (Integer) v;
        } else if (v instanceof String) {
          try {
            return Integer.parseInt((String) v);
          } catch (NumberFormatException e) {
            return 0;
          }
        }
        return 0;
      }

      @Override public long longVal(int doc) {
        return intVal(doc);
      }

      @Override public double doubleVal(int doc) {
        return floatVal(doc);
      }

      @Override public String strVal(int doc) {
        final String id = lookup[doc];
        if (obj == null) return null;
        Object v = obj.get(id);
        return v != null ? v.toString() : null;
      }

      @Override public String toString(int doc) {
        return strVal(doc);
      }
    };
  }
 

You can now use the FunctionQuery mongo in your search requests. For example:
http://localhost:8983/solr/select?defType=edismax&q=cat:electronics&bf=mongo(1377)