线上业务准备使用solr做数据存放和索引的功能,其中有的字段要求会存入多个字,solr的field的
multivalue可以实现这个功能。

1
< 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.
看看其具体实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
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的实现如下:

1
2
3
4
5
6
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类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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:

1
2
3
4
5
6
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:

1
2
3
4
5
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的追加都是对本次实例说的)。



本文转自菜菜光 51CTO博客,原文链接:http://blog.51cto.com/caiguangguang/1433761,如需转载请自行联系原作者