线上业务准备使用solr做数据存放和索引的功能,其中有的字段要求会存入多个字,solr的field的
multivalue可以实现这个功能。
<dynamicField name="*_ss" type="string" indexed="true" stored="true" multiValued="true"/>
下面看看其实现原理:
和solr的写入document相关的两个类是SolrInputDocument 和SolrInputField,其中SolrInputDocument 是和整条document有关,SolrInputField 是和field相关(属性包含field的名称,值和boost值)。
SolrInputDocument 类中和document添加的方法主要有addField 和setField,其中setField是覆盖前面的value,addField是追加value.
看看其具体实现:
public SolrInputDocument() { _fields = new LinkedHashMap <String,SolrInputField>(); // 通过构造方法构建一个map,value是SolrInputField } private final Map<String,SolrInputField> _fields; public void addField(String name, Object value, float boost ) //addFiled的方法中,参数value是个object SolrInputField field = _fields.get( name ); // name是指field的名称,value是指field的值,判断map中是否已经有这个field的信息 if( field == null || field.value == null ) { // 如果filed或者filed value为空,就用本类的setField(即第一次添加有效地值,类似于overwrite) setField(name, value, boost); } else { field.addValue( value, boost ); // 否则用SolrInputField的addValue方法(类似于append) } }
其中setField的实现如下:
public void setField(String name, Object value, float boost ) { SolrInputField field = new SolrInputField( name ); _fields.put( name, field ); field.setValue( value, boost ); //其实是调用了SolrInputField的setValue方法 }
再来看看SolrInputField类:
public class SolrInputField implements Iterable<Object>, Serializable { String name; Object value = null; float boost = 1.0f; public SolrInputField( String n ) { this. name = n; } public void setValue(Object v, float b) { boost = b; if( v instanceof Object[] ) { // Arrays will be converted to a collection.如果传入的value是个list,会转换为collection Object[] arr = (Object[])v; Collection<Object> c = new ArrayList<Object>( arr.length ); for( Object o : arr ) { c.add( o ); } value = c; } else { value = v; } } public void addValue(Object v, float b) { //可以看到同样会判断是否为collection if( value == null ) { if ( v instanceof Collection ) { Collection<Object> c = new ArrayList<Object>( 3 ); for ( Object o : (Collection<Object>)v ) { c.add( o ); } setValue(c, b); } else { setValue(v, b); } return; }
....
通过上面可以看出,在向field传入value的时候,是可以传入数组这种数据结构的,这样,就可以在一个field里面插入多个value
比如下面的两种方法,都可以写入同一个field多个有效值:
例1:
SolrInputDocument doc = new SolrInputDocument(); String key = "123"; doc.addField("id", key); doc.addField("test_ss", "vv1"); doc.addField("test_ss", "vv2"); doc.addField("test_ss", "vv3");
例2:
SolrInputDocument doc = new SolrInputDocument(); String key = "123"; String[] vv = {"vv1","vv2","vv3"}; doc.addField("id", key); doc.addField("test_ss", vv);
注意,每次实例化一个SolrInputDocument 的对象,都相当于对这一行进行重新overwrite的操作,因为solr是基于lucene的,lucene的update是通过delete+add实现的。也就是如果一个document为id:1,test_ss:aa,在后面重新实例化后,对于相同的id记录,使用addFiled("test_ss","bb")之后document变为id:1,test_ss:bb了。。(setField的覆盖和addField的追加都是对本次实例说的)。