目錄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)
感謝閱讀, 若是文章有幫助或啓發到你, 點個[好文要頂👆] 或 [推薦👍] 吧😜
本文版權歸博主全部, 歡迎轉載, 但 [必須在文章頁面明顯位置標明原文連接], 不然博主保留追究相關人員法律責任的權利.