Using MongoDB from within Solr for boosting documents
Posted by Kelvin on 09 Jun 2012 at 01:43 am | Tagged as: Lucene / Solr / Elasticsearch / Nutch
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)