目录javascript
(1) 需求:html
向Solr中的文档添加新的字段并赋值, 或者修改已有的字段, 对不修改的要保持原值, 也就是不能进行彻底覆盖操做.java
(2) 前提:apache
添加的字段(field)要提早在schema.xml文件中定义, 不然Solr没法处理这些字段, 确定会致使添加失败.
关于schema.xml文件的配置, 可参考: Solr的schema.xml模式文件解读 (Solr的模式设计与优化)bash
(3) 分析: 咱们可使用Solr提供的原子更新, 来实现相关需求:并发
Solr支持的原子更新:
set
: 修改指定文档中该field的值, 若是这个field已经存在, 则更新, 若是不存在, 则追加到这个文档中 —— 能够是单值, 也能够是multi-valued;
add
: 向指定文档中的field字段添加值, 这个field必须是multi-valued类型的, 不然将出错 —— 只能是multi-valued;
inc
: 对指定文档中数值类型的值进行自增操做 —— 只能是数值类型, 包括int、long、float、double.优化
<!-- 项目较早, 使用的是4.10.4版本的Solr --> <dependency> <groupId>org.apache.solr</groupId> <artifactId>solr-solrj</artifactId> <version>4.10.4</version> </dependency>
(1) 先获取Solr链接:this
String zkHost= "ip:port,ip:port,ip:port"; // 扩大并发链接数 ModifiableSolrParams params = new ModifiableSolrParams(); params.set(HttpClientUtil.PROP_MAX_CONNECTIONS, 1000); params.set(HttpClientUtil.PROP_MAX_CONNECTIONS_PER_HOST, 100); HttpClient client = HttpClientUtil.createClient(params); LBHttpSolrServer lbServer = new LBHttpSolrServer(client); CloudSolrServer solrServer = new CloudSolrServer(zkHost, lbServer); // 为 Solr 链接设置默认的 Collection solrServer.setDefaultCollection("C_Book"); // 设置ZooKeeper链接超时时间 solrServer.setZkClientTimeout(18000); solrServer.setZkConnectTimeout(36000);
(2) 准备须要处理的Solr文档, 相关注意事项已经在代码注释中做了详细说明:设计
// 为了提升效率, 可使用批量操做 Collection<SolrInputDocument> updateDocList = new ArrayList<>(); for (int i = 0; i < 5; ++i) { SolrInputDocument doc = new SolrInputDocument(); // 局部更新须要指定文档的id(在schema.xml中配置的主键), // 主键不须要添加set、add等信息, 其余须要原子更新的field须要构造为Map doc.addField("id", i); // 局部更新须要借助Map, 这个Map的Key必须是“set” Map<String, String> publisherMap = new HashMap<>(); publisherMap.put("set", "人民邮电出版社"); // 修改图书的出版社, key是field, value是上述的Map doc.addField("publisher", publisherMap); // 在已有仓库的基础上, 再添加多个仓库, 注意: 此field必须是multi-valued类型 Map<String, List<String>> stockCityMap = new HashMap<>(); List<String> list = new ArrayList(); list.add("广州"); list.add("深圳"); // 局部添加须要借助Map, 这个Map的Key必须是“add” stockCityMap.put("add", list); // 修改图书的仓库城市, key是field, value是上述的Map doc.addField("stockCity", stockCityMap); // 在已有图书价格的基础上: 每本增长9.50元, 注意: 此field必须是数值类型 Map<String, Long> priceMap = new HashMap<>(); // 局部自增须要借助Map, 这个Map的Key必须是“inc” priceMap.put("inc", 9.50L); // 修改图书的价格, key是field, value是上述的Map doc.addField("price", priceMap); // _version_值为0: 若是待修改的文档存在, 则修改; 若是不存在, 则添加 doc.addField("_version_", 0); updateDocList.add(doc); }
(3) 向SolrCloud中提交批量添加请求:code
// 链接SolrCloud solrServer.connect(); // 添加提交文档List UpdateResponse rsp = solrServer.add(updateDocList); System.out.println("操做状态: " + rsp.getStatus() + ", 操做时间:" + rsp.getQTime()); // 提交策略: 不用手动提交, 交由Solr服务根据配置自动进行软提交; // 若是要手动提交, 不要使用无参方法, 推荐指定提交策略: 是否等待刷新(建议不等待: 会阻塞)、等待可搜索(建议不等待: 会阻塞)、软提交 UpdateResponse rspCommit = solrServer.commit(false, false, true); System.out.println("提交状态: " + " result:" + rspCommit.getStatus() + ", 操做时间: " + rspCommit.getQTime());
(1) version < 0
: 若是待修改的文档存在, Solr会拒绝修改; 若是不存在, 就添加这个文档.
(2) version = 0
: 若是待修改的文档存在, 就更新这个文档; 若是不存在, 就添加这个文档.
(3) version = 1
: 若是待修改待文档存在, 就更新这个文档; 若是不存在, Solr会拒绝修改它, 并抛出相似的错误信息:
version conflict for 1 expected=1 actual=-1
(4) version > 1
: 若是文档的_version_
值和传入的_version_
值不一样, Solr就会拒绝修改; 值相同时才执行修改.
(1) 若是某个字段在schema.xml中指定了store=false
, 那么即便这个字段有值, 在更新的时候也会被Solr丢弃, 而指定为store=true
的字段则不会;
(2) 对于multi-field(多值)字段, 若是指定其store=false
, 则在原子更新使用add
的时候会级联清除该字段以前的数据.
参考资料
版权声明
出处: 博客园 马瘦风的博客(https://www.cnblogs.com/shoufeng)
感谢阅读, 若是文章有帮助或启发到你, 点个[好文要顶👆] 或 [推荐👍] 吧😜
本文版权归博主全部, 欢迎转载, 但 [必须在文章页面明显位置标明原文连接], 不然博主保留追究相关人员法律责任的权利.