先说下背景吧,最近接手一个新项目,由于公司原来项目中用的solr更新数据一直是晚上定时与数据库做同步,这个新项目中由于需求需要对某些更改的数据在solr搜索出来的数据中中用户可以及时看到数据的更新,那么问题来了,这就涉及到对solr的原子更新了,在网上查了各种资料,大部分都是这样做的
SolrInputDocument solrInputDocument = new SolrInputDocument();
solrInputDocument.addField("id", id);
Map<String, String > operation = new HashMap<>();
operation.put("set", "test1");
solrInputDocument.addField("title", operation);
solrServer.add(solrInputDocument);
solrServer.commit();
基本都是用一个map对单个索引字段进行更新,这样也能更新成功,不过要注意的是索引字段必须store=true,如果store为false,更新后字段会丢失。
上面的方式不太符合我的需求,由于solr建立索引字段太多,所以根据map一个一个字段更新太麻烦,所以直接用一个实体更新
定义一个文章实体,包括id,标题,时间,作者,内容
import java.util.Arrays;
import java.util.Date;
import org.apache.solr.client.solrj.beans.Field;
import org.springframework.data.annotation.Id;
public class Article {
@Id
@Field
private String id;
@Field
private String[] title;
@Field
private Date[] time;
@Field
private String[] author;
@Field
private String[] info;
// 省略getter和setter
}
初始化(连接solr)
private static SolrClient client;
private static String url;
static {
url = "http://localhost:8983/solr/mycollections";
client = new HttpSolrClient.Builder(url).build();
}
添加/更新方法
/**
* 保存或者更新solr数据
*
* @param res
*/
public static boolean saveSolrResource(Article article) {
DocumentObjectBinder binder = new DocumentObjectBinder();
// 传入一个文章实体,里面包括solr索引的所有字段
SolrInputDocument doc = binder.toSolrInputDocument(article);
try {
client.add(doc);
System.out.println(client.commit());
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
以上就能完成多solr单条数据多个字段进行更新,不过我在实际操作中遇到了一个问题,
插入数据报错:Solr Error This Indexschema is not mutable
意思是schema.xml是不可变的 ,又去查了大量资料才发现因为schema.xml是用户定义的,solr无权修改,所以需要禁用solr 更改field的特性
在solrconfig.xml这个配置文件里找到updateRequestProcessorChain这个标签把AddSchemaFieldsUpdateProcessorFactory这个class注释掉,重新启动Solr