首页 > 代码库 > solr multivalue的实现分析

solr multivalue的实现分析

  线上业务准备使用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的追加都是对本次实例说的)。

本文出自 “菜光光的博客” 博客,请务必保留此出处http://caiguangguang.blog.51cto.com/1652935/1433761