简介
SolrJ是一个API,它使用Java(或任何基于JVM的语言)编写的应用程序可以轻松地与Solr交谈。SolrJ隐藏了许多连接到Solr的细节,并允许您的应用程序通过简单的高级方法与Solr交互。SolrJ支持大多数Solr API,并且具有高度可配置性。
官方API参考文档: https://lucene.apache.org/solr/guide
- 工程搭建
pom.xml依赖:
<dependency><groupId>org.apache.solr</groupId><artifactId>solr-solrj</artifactId><version>7.7.2</version></dependency>
注意:如果不用maven构建项目,只需要将solr-solrj-*.jar和在dist/solrj-lib目录中的依赖包放入到工程中。
SolrJ连接
1. HttpSolrClient(单机Solr)
SolrClient是一个抽象类,下边有很多被实现的子类,如:“HttpSolrClient”(面向以查询为中心的工作负载) ,但也是一个很好的通用客户端。直接与单个Solr节点通信。不同solr版本solrj 的创建方式有所不同。
// solr4创建方式SolrServer solrServer = new HttpSolrServer(solrUrl);// solr5创建方式,在url中指定core名称:core1HttpSolrClient solrClient = new HttpSolrClient(solrUrl);// solr7创建方式,在url中指定core名称:core1HttpSolrClient solrClient = new HttpSolrClient.Builder(solrUrl).build();
示例:
import org.apache.solr.client.solrj.impl.HttpSolrClient;/***** @Description 连接Solr,使用运行中的某一台solr节点*/public class Test01Connection {// 声明一个连接solr的地址(ip:port/solr/库名)public static final String SOLR_URL = "http://bigdata-node1:8983/solr/db_sync";// 声明一个连接solr的对象private static HttpSolrClient httpSolrClient;static {// 创建solrClient同时指定超时时间,不指定走默认配置httpSolrClient = new HttpSolrClient.Builder(SOLR_URL).withConnectionTimeout(10000).withSocketTimeout(60000).build();}public static void main(String[] args) {System.out.println(httpSolrClient);}}
2. CloudSolrClient(Solr集群)
CloudSolrClient(面向与SolrCloud部署的通信),使用已记录的ZooKeeper状态来发现并将请求路由到健康的Solr节点。有两种不同的接入方式,第一种方式:使用运行中的某一台solr节点;第二种方式:使用zookeeper节点连接(推荐)。
■ 通过Solr URL连接集群
import org.apache.solr.client.solrj.SolrQuery;import org.apache.solr.client.solrj.SolrServerException;import org.apache.solr.client.solrj.impl.CloudSolrClient;import org.apache.solr.client.solrj.response.QueryResponse;import org.apache.solr.common.SolrDocument;import org.apache.solr.common.SolrDocumentList;import java.io.IOException;import java.util.ArrayList;import java.util.List;/***** @Description 全查询*/public class Test14SolrCloudQueryAll {// 声明一个连接solr的对象private static CloudSolrClient cloudSolrClient;static {List<String> solrUrls = new ArrayList<>();solrUrls.add("http://ltsr003:8983/solr");solrUrls.add("http://ltsr005:8983/solr");solrUrls.add("http://ltsr006:8983/solr");cloudSolrClient = new CloudSolrClient.Builder(solrUrls).build();cloudSolrClient.setDefaultCollection("db_sync");}public static void main(String[] args) throws IOException, SolrServerException {String keywords = "*:*";// 创建一个查询条件对象SolrQuery solrQuery = new SolrQuery(keywords);// 查询QueryResponse query = cloudSolrClient.query(solrQuery);// 取出结果SolrDocumentList results = query.getResults();System.out.println("总条数:" + results.getNumFound());for (SolrDocument result : results) {System.out.println(result);}}}
■ 通过ZooKeeper连接集群(推荐)
import org.apache.solr.client.solrj.SolrQuery;import org.apache.solr.client.solrj.SolrServerException;import org.apache.solr.client.solrj.impl.CloudSolrClient;import org.apache.solr.client.solrj.response.QueryResponse;import org.apache.solr.common.SolrDocument;import org.apache.solr.common.SolrDocumentList;import java.io.IOException;import java.util.ArrayList;import java.util.List;import java.util.Optional;/***** @Description 全查询(zk)*/public class Test15SolrCloudQueryAll {// 声明一个连接solr的对象private static CloudSolrClient cloudSolrClient;static {List<String> zkHosts = new ArrayList<>();zkHosts.add("192.168.0.15:2181");zkHosts.add("192.168.0.16:2181");zkHosts.add("192.168.0.17:2181");cloudSolrClient = new CloudSolrClient.Builder(zkHosts, Optional.empty()).build();cloudSolrClient.setDefaultCollection("db_sync");cloudSolrClient.setZkClientTimeout(5000);cloudSolrClient.setZkConnectTimeout(5000);}public static void main(String[] args) throws IOException, SolrServerException {String keywords = "*:*";// 创建一个查询条件对象SolrQuery solrQuery = new SolrQuery(keywords);// 查询QueryResponse query = cloudSolrClient.query(solrQuery);// 取出结果SolrDocumentList results = query.getResults();System.out.println("总条数:" + results.getNumFound());for (SolrDocument result : results) {System.out.println(result);}cloudSolrClient.close();}}
案例
01. 新增数据
1. 新增单条记录
import org.apache.solr.client.solrj.SolrServerException;import org.apache.solr.client.solrj.impl.HttpSolrClient;import org.apache.solr.common.SolrInputDocument;import java.io.IOException;/**** @Description 新增数据(单条) <br/>* 创建索引库:<br/>* https://www.yuque.com/polaris-docs/bigdata/solr-op* {* "id":"1",* "content_id":10,* "title":"我是中国人",* "content":"作为一个中国人,我感到很自豪。",* "type":1,* "create_at":1578912614123,* "publish_at":1578912614123* }*/public class Test02AddRecord {// 声明一个连接solr的地址(ip:port/solr/库名)public static final String SOLR_URL = "http://bigdata-node1:8983/solr/db_sync";// 声明一个连接solr的对象private static HttpSolrClient httpSolrClient;static {httpSolrClient = new HttpSolrClient.Builder(SOLR_URL).build();}public static void main(String[] args) throws IOException, SolrServerException {addOneByOne();}private static void addOneByOne() throws SolrServerException, IOException {// 一个个添加SolrInputDocument doc = new SolrInputDocument();// id不给值将自动生成UUIDdoc.addField("id", 2);doc.addField("content_id", 101L);doc.addField("title", "我是中国人,打到小日本");doc.addField("content", "作为一个中国人,我感到很自豪。");doc.addField("type", 1);doc.addField("create_at", 1578912614123L);doc.addField("publish_at", 1578912614123L);httpSolrClient.add(doc);httpSolrClient.commit();httpSolrClient.close();System.out.println("操作成功");}}
2. 新增多条记录
■ 文档对象列表方式(List)
import org.apache.solr.client.solrj.SolrServerException;import org.apache.solr.client.solrj.impl.HttpSolrClient;import org.apache.solr.common.SolrInputDocument;import java.io.IOException;import java.util.ArrayList;import java.util.List;/**** @Description 新增数据(批量) <br/>* 创建索引库:<br/>* https://www.yuque.com/polaris-docs/bigdata/solr-op* {* "id":"1",* "content_id":10,* "title":"我是中国人",* "content":"作为一个中国人,我感到很自豪。",* "type":1,* "create_at":1578912614123,* "publish_at":1578912614123* }*/public class Test04AddRecords {// 声明一个连接solr的地址(ip:port/solr/库名)public static final String SOLR_URL = "http://bigdata-node1:8983/solr/db_sync";// 声明一个连接solr的对象private static HttpSolrClient httpSolrClient;static {httpSolrClient = new HttpSolrClient.Builder(SOLR_URL).build();}public static void main(String[] args) throws IOException, SolrServerException {addByList();}private static void addByList() throws SolrServerException, IOException {// 一个集合一个集合的添加List<SolrInputDocument> docs = new ArrayList<>();for (int i = 199; i <= 204; i++) {SolrInputDocument doc = new SolrInputDocument();// id不给值将自动生成UUIDdoc.addField("id", i);doc.addField("content_id", i * 10L);doc.addField("title", "我是中国人,打倒小日本" + i);doc.addField("content", "作为一个中国人,我感到很自豪。");doc.addField("type", 1);doc.addField("create_at", 1578912614123L);doc.addField("publish_at", 1578912614123L);docs.add(doc);}httpSolrClient.add(docs);httpSolrClient.commit();httpSolrClient.close();System.out.println("操作成功");}}
■ 注解方式(Pojo Annotation)
package com.lonton.bigdata.pojo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import org.apache.solr.client.solrj.beans.Field;/*** @author polaris <450733605@qq.com>* Description Pojo-文章类* Date 2020-8-19 20:13* Version 1.0.0*/@Data@AllArgsConstructor@NoArgsConstructorpublic class Article {@Field("id")private Integer id;@Field("content_id")private Long contentId;@Field("title")private String title;@Field("content")private String content;@Field("type")private Integer type;@Field("create_at")private Long createAt;@Field("publish_at")private Long publishAt;@Overridepublic String toString() {return "Article{" +"id=" + id +", contentId=" + contentId +", title='" + title + '\'' +", content='" + content + '\'' +", type=" + type +", createAt=" + createAt +", publishAt=" + publishAt +'}';}}
import com.lonton.bigdata.pojo.Article;import org.apache.solr.client.solrj.SolrServerException;import org.apache.solr.client.solrj.impl.HttpSolrClient;import java.io.IOException;import java.util.ArrayList;import java.util.List;/**** @Description 新增数据(注解方式) <br/>* 创建索引库:<br/>* https://www.yuque.com/polaris-docs/bigdata/solr-op* {* "id":"1",* "content_id":10,* "title":"我是中国人",* "content":"作为一个中国人,我感到很自豪。",* "type":1,* "create_at":1578912614123,* "publish_at":1578912614123* }*/public class Test05AddRecordsAnnotation {// 声明一个连接solr的地址(ip:port/solr/库名)public static final String SOLR_URL = "http://bigdata-node1:8983/solr/db_sync";// 声明一个连接solr的对象private static HttpSolrClient httpSolrClient;static {httpSolrClient = new HttpSolrClient.Builder(SOLR_URL).build();}public static void main(String[] args) throws IOException, SolrServerException {List<Article> pojo = new ArrayList<>(5);for (int i = 205; i <= 235; i++) {pojo.add(new Article(i, i * 10L, "我是中国人,打倒小日本" + i, "作为一个中国人,我感到很自豪。", 1, 1578912614123L, 1578912614123L));}httpSolrClient.addBeans(pojo);httpSolrClient.commit();httpSolrClient.close();System.out.println("操作成功");}}
02. 删除数据
package com.lonton.bigdata.solr;import org.apache.solr.client.solrj.SolrServerException;import org.apache.solr.client.solrj.impl.HttpSolrClient;import java.io.IOException;import java.util.Arrays;public class Test03DeleteRecords {// 声明一个连接solr的地址(ip:port/solr/库名)public static final String SOLR_URL = "http://bigdata-node1:8983/solr/db_sync";// 声明一个连接solr的对象private static HttpSolrClient httpSolrClient;static {httpSolrClient = new HttpSolrClient.Builder(SOLR_URL).build();}public static void main(String[] args) throws IOException, SolrServerException {// 方式1:根据ID删除(单行)httpSolrClient.deleteById("1");// 方式2:根据ID的集合删除(单行/多行)httpSolrClient.deleteById(Arrays.asList("199", "200", "201"));// 方式3:根据查询结果删除(单行/多行)// 示例:全部删除httpSolrClient.deleteByQuery("*:*");httpSolrClient.commit();httpSolrClient.close();System.out.println("操作成功");}}
03. 查询数据
1. 全表扫描
import org.apache.solr.client.solrj.SolrQuery;import org.apache.solr.client.solrj.SolrServerException;import org.apache.solr.client.solrj.impl.HttpSolrClient;import org.apache.solr.client.solrj.response.QueryResponse;import org.apache.solr.common.SolrDocument;import org.apache.solr.common.SolrDocumentList;import java.io.IOException;/***** @Description 全表扫描*/public class Test06QueryAll {// 声明一个连接solr的地址(ip:port/solr/库名)public static final String SOLR_URL = "http://bigdata-node1:8983/solr/db_sync";// 声明一个连接solr的对象private static HttpSolrClient httpSolrClient;static {httpSolrClient = new HttpSolrClient.Builder(SOLR_URL).build();}public static void main(String[] args) throws IOException, SolrServerException {String keywords = "*:*";// 创建一个查询条件对象SolrQuery solrQuery = new SolrQuery(keywords);// 查询QueryResponse query = httpSolrClient.query(solrQuery);// 取出结果SolrDocumentList results = query.getResults();System.out.println("总条数:" + results.getNumFound());for (SolrDocument result : results) {System.out.println(result);}}}
2. 分页查询
import org.apache.solr.client.solrj.SolrQuery;import org.apache.solr.client.solrj.SolrServerException;import org.apache.solr.client.solrj.impl.HttpSolrClient;import org.apache.solr.client.solrj.response.QueryResponse;import org.apache.solr.common.SolrDocument;import org.apache.solr.common.SolrDocumentList;import java.io.IOException;/***** @Description 分页查询*/public class Test07QueryForPage {// 声明一个连接solr的地址(ip:port/solr/库名)public static final String SOLR_URL = "http://bigdata-node1:8983/solr/db_sync";// 声明一个连接solr的对象private static HttpSolrClient httpSolrClient;static {httpSolrClient = new HttpSolrClient.Builder(SOLR_URL).build();}public static void main(String[] args) throws IOException, SolrServerException {String keywords = "*:*";// 创建一个查询条件对象SolrQuery solrQuery = new SolrQuery(keywords);int page = 2; // 第2页int limit = 2; // 每页显示条数solrQuery.setStart((page - 1) * limit); // 设置从哪里开始查,不查页码solrQuery.setRows(limit); // 设置每页显示多少条// 查询QueryResponse query = httpSolrClient.query(solrQuery);// 取出结果SolrDocumentList results = query.getResults();System.out.println("总条数:" + results.getNumFound());for (SolrDocument result : results) {System.out.println(result);}}}
3. 排序
import org.apache.solr.client.solrj.SolrQuery;import org.apache.solr.client.solrj.SolrServerException;import org.apache.solr.client.solrj.impl.HttpSolrClient;import org.apache.solr.client.solrj.response.QueryResponse;import org.apache.solr.common.SolrDocument;import org.apache.solr.common.SolrDocumentList;import java.io.IOException;/***** @Description 排序*/public class Test08QuerySort {// 声明一个连接solr的地址(ip:port/solr/库名)public static final String SOLR_URL = "http://bigdata-node1:8983/solr/db_sync";// 声明一个连接solr的对象private static HttpSolrClient httpSolrClient;static {httpSolrClient = new HttpSolrClient.Builder(SOLR_URL).build();}public static void main(String[] args) throws IOException, SolrServerException {String keywords = "*:*";// 创建一个查询条件对象SolrQuery solrQuery = new SolrQuery(keywords);// 只能根据一个属性进行排序solrQuery.setSort("id", SolrQuery.ORDER.desc);// 查询QueryResponse query = httpSolrClient.query(solrQuery);// 取出结果SolrDocumentList results = query.getResults();System.out.println("总条数:" + results.getNumFound());for (SolrDocument result : results) {System.out.println(result);}}}
4. 高亮显示
import com.lonton.bigdata.pojo.Article;import org.apache.solr.client.solrj.SolrQuery;import org.apache.solr.client.solrj.SolrServerException;import org.apache.solr.client.solrj.impl.HttpSolrClient;import org.apache.solr.client.solrj.response.QueryResponse;import org.apache.solr.common.SolrDocument;import org.apache.solr.common.SolrDocumentList;import org.apache.solr.common.StringUtils;import java.io.IOException;import java.util.ArrayList;import java.util.List;import java.util.Map;/***** @Description 高亮显示*/public class Test09QueryHeightLight {// 声明一个连接solr的地址(ip:port/solr/库名)public static final String SOLR_URL = "http://bigdata-node1:8983/solr/db_sync";// 声明一个连接solr的对象private static HttpSolrClient httpSolrClient;static {httpSolrClient = new HttpSolrClient.Builder(SOLR_URL).build();}public static void main(String[] args) throws IOException, SolrServerException {List<Article> articleList = new ArrayList<>();String keywords = "title:中国人";// 创建一个查询条件对象SolrQuery solrQuery = new SolrQuery(keywords);// 开户高亮solrQuery.setHighlight(true);// 设置要进行高亮的属性solrQuery.addHighlightField("title");solrQuery.addHighlightField("content");// 设置高亮的前后缀solrQuery.setHighlightSimplePre("<font color=red>");solrQuery.setHighlightSimplePost("</font>");// 查询QueryResponse query = httpSolrClient.query(solrQuery);// 取出结果SolrDocumentList results = query.getResults();// 取出高亮的结果Map<String, Map<String, List<String>>> highlighting = query.getHighlighting();System.out.println("总条数:" + results.getNumFound());for (SolrDocument result : results) { // 搜索处理的每个文档,进文档里面的内容进行高亮Article pojo = new Article();pojo.setId(Integer.valueOf(result.getFieldValue("id").toString()));pojo.setContentId(Long.valueOf(result.getFieldValue("content_id").toString()));pojo.setTitle(result.getFieldValue("title").toString());pojo.setContent(result.getFieldValue("content").toString());pojo.setType(Integer.valueOf(result.getFieldValue("type").toString()));pojo.setCreateAt(Long.valueOf(result.getFieldValue("create_at").toString()));pojo.setPublishAt(Long.valueOf(result.getFieldValue("publish_at").toString()));String id = (String) result.getFieldValue("id");Map<String, List<String>> listMap = highlighting.get(id);if (null != listMap && !listMap.isEmpty()) {List<String> title = listMap.get("title");List<String> content = listMap.get("content");if (title != null && !StringUtils.isEmpty(title.get(0))) {pojo.setTitle(title.get(0));}if (content != null && !StringUtils.isEmpty(content.get(0))) {pojo.setContent(content.get(0));}}articleList.add(pojo);}for (Article article : articleList) {System.out.println(article);}}}
5. 范围查询
import org.apache.solr.client.solrj.SolrQuery;import org.apache.solr.client.solrj.SolrServerException;import org.apache.solr.client.solrj.impl.HttpSolrClient;import org.apache.solr.client.solrj.response.QueryResponse;import org.apache.solr.common.SolrDocument;import org.apache.solr.common.SolrDocumentList;import java.io.IOException;/***** @Description 范围查询*/public class Test10QueryRange {// 声明一个连接solr的地址(ip:port/solr/库名)public static final String SOLR_URL = "http://bigdata-node1:8983/solr/db_sync";// 声明一个连接solr的对象private static HttpSolrClient httpSolrClient;static {httpSolrClient = new HttpSolrClient.Builder(SOLR_URL).build();}public static void main(String[] args) throws IOException, SolrServerException {// 创建条件SolrQuery solrQuery = new SolrQuery("*:*");// 限定范围(<=?)solrQuery.setFilterQueries("id:[* TO 205]");// 限定范围(>=? and <=?)solrQuery.setFilterQueries("id:[205 TO 207]");// 限定范围(>=?)solrQuery.setFilterQueries("id:[207 TO *]");QueryResponse query = httpSolrClient.query(solrQuery);// 取出结果SolrDocumentList results = query.getResults();System.out.println("总条数:" + results.getNumFound());for (SolrDocument result : results) {System.out.println(result);}}}
6. 过滤
import org.apache.solr.client.solrj.SolrQuery;import org.apache.solr.client.solrj.SolrServerException;import org.apache.solr.client.solrj.impl.HttpSolrClient;import org.apache.solr.client.solrj.response.QueryResponse;import org.apache.solr.common.SolrDocument;import org.apache.solr.common.SolrDocumentList;import java.io.IOException;/***** @Description 过滤查询*/public class Test11QueryFilter {// 声明一个连接solr的地址(ip:port/solr/库名)public static final String SOLR_URL = "http://bigdata-node1:8983/solr/db_sync";// 声明一个连接solr的对象private static HttpSolrClient httpSolrClient;static {httpSolrClient = new HttpSolrClient.Builder(SOLR_URL).build();}public static void main(String[] args) throws IOException, SolrServerException {// 创建条件SolrQuery solrQuery = new SolrQuery("*:*");// 限定条件 id=205solrQuery.setFilterQueries("id:205");QueryResponse query = httpSolrClient.query(solrQuery);// 取出结果SolrDocumentList results = query.getResults();System.out.println("总条数:" + results.getNumFound());for (SolrDocument result : results) {System.out.println(result);}}}
7. 关键字查询(复制域-copyField)
import org.apache.solr.client.solrj.SolrQuery;import org.apache.solr.client.solrj.SolrServerException;import org.apache.solr.client.solrj.impl.HttpSolrClient;import org.apache.solr.client.solrj.response.QueryResponse;import org.apache.solr.common.SolrDocument;import org.apache.solr.common.SolrDocumentList;import java.io.IOException;/***** @author polaris <450733605@qq.com>* @Description 关键字查询(复制域) <br/>* 注意:修改Schema后,新增的数据才能通过关键字查询* <field name="title" type="text_ik" uninvertible="true" indexed="true" stored="true"/>* <field name="content" type="text_ik" uninvertible="true" indexed="true" stored="true"/>* <field name="keywords" type="text_ik" uninvertible="false" multiValued="true" indexed="true" stored="true"/>* <copyField source="title" dest="keywords"/>* <copyField source="content" dest="keywords"/>*/public class Test12QueryKeywords {// 声明一个连接solr的地址(ip:port/solr/库名)public static final String SOLR_URL = "http://bigdata-node1:8983/solr/db_sync";// 声明一个连接solr的对象private static HttpSolrClient httpSolrClient;static {httpSolrClient = new HttpSolrClient.Builder(SOLR_URL).build();}public static void main(String[] args) throws IOException, SolrServerException {// 创建条件SolrQuery solrQuery = new SolrQuery("keywords:中国");QueryResponse query = httpSolrClient.query(solrQuery);// 取出结果SolrDocumentList results = query.getResults();System.out.println("总条数:" + results.getNumFound());for (SolrDocument result : results) {System.out.println(result);}}}
注意:修改**Schema**后,新增的数据才能通过关键字查询。
8. 综合查询
import org.apache.solr.client.solrj.SolrQuery;import org.apache.solr.client.solrj.impl.HttpSolrClient;import org.apache.solr.client.solrj.response.QueryResponse;import org.apache.solr.common.SolrDocument;import org.apache.solr.common.SolrDocumentList;import org.apache.solr.common.StringUtils;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/***** @Description 综合查询*/public class Test13QueryComprehensive {// 声明一个连接solr的地址(ip:port/solr/库名)public static final String SOLR_URL = "http://bigdata-node1:8983/solr/db_sync";// 声明一个连接solr的对象private static HttpSolrClient httpSolrClient;static {httpSolrClient = new HttpSolrClient.Builder(SOLR_URL).build();}public static void main(String[] args) {Map<String, String> filter = new HashMap<>();filter.put("id", "205");List<Map<String, Object>> list = queryAll("中国", 1, 10, 1, "205-209", filter);for (Map<String, Object> map : list) {System.out.println(map);}}/**** @Description: 综合查询* @Param:* [* keywords, 关键字* page, 页码* limit, 每页条数* sort, 排序规则:1-升;0-降序* range, 范围 start-end* filter 过滤条件* ]* @return*/public static List<Map<String, Object>> queryAll(String keywords, int page, int limit, int sort, String range, Map<String, String> filter) {// 条件构造SolrQuery solrQuery = new SolrQuery("keywords:" + keywords);// 分页处理solrQuery.setStart((page - 1) * limit);solrQuery.setRows(limit);// 排序switch (sort) {case 0:solrQuery.addSort("id", SolrQuery.ORDER.desc);break;case 1:solrQuery.addSort("id", SolrQuery.ORDER.asc);break;}// 范围和过滤条件的处理List<String> fqList = new ArrayList<>();if (!StringUtils.isEmpty(range)) {if (!range.contains("-")) {throw new RuntimeException("范围参数不合法");}String[] split = range.split("-");fqList.add("id:[" + split[0] + " TO " + split[1] + "]");}if (filter != null && !filter.isEmpty()) {filter.forEach((k, v) -> {fqList.add(k + ":" + v);});}if (!fqList.isEmpty()) {solrQuery.setFilterQueries(fqList.toArray(new String[]{}));}// 处理高亮// 设置要进行高亮的属性solrQuery.addHighlightField("title");solrQuery.addHighlightField("content");// 设置高亮的前后缀solrQuery.setHighlightSimplePre("<font color=red>");solrQuery.setHighlightSimplePost("</font>");try {List<Map<String, Object>> listMaps = new ArrayList<>();QueryResponse query = httpSolrClient.query(solrQuery);SolrDocumentList results = query.getResults();Map<String, Map<String, List<String>>> highlighting = query.getHighlighting();System.out.println("总条数:" + results.getNumFound());for (SolrDocument result : results) {Map<String, Object> map = new HashMap<>();map.put("id", result.getFieldValue("id"));map.put("content_id", result.getFieldValue("content_id"));map.put("title", result.getFieldValue("title"));map.put("content", result.getFieldValue("content"));map.put("type", result.getFieldValue("type"));map.put("create_at", result.getFieldValue("create_at"));map.put("publish_at", result.getFieldValue("publish_at"));Map<String, List<String>> listMap = highlighting.get(map.get("id"));if (null != listMap && !listMap.isEmpty()) {String title = listMap.get("title").get(0);String content = listMap.get("content").get(0);map.put("title", title);map.put("content", content);}listMaps.add(map);}return listMaps;} catch (Exception e) {e.printStackTrace();}return null;}}
SolrJ API
■ 常量类(Constant.java)
public class Constant {/** Solr配置 **/public static class SolrConfig {public final static String SOLR_URL="http://bigdata-node1:8983/solr/db_sync";}}
■ 工具类(SolrUtil.java)
import java.io.IOException;import java.lang.reflect.Field;import java.util.*;import com.lonton.bigdata.constant.Constant;import org.apache.commons.beanutils.BeanUtils;import org.apache.solr.client.solrj.SolrQuery;import org.apache.solr.client.solrj.SolrServerException;import org.apache.solr.client.solrj.beans.DocumentObjectBinder;import org.apache.solr.client.solrj.impl.HttpSolrClient;import org.apache.solr.client.solrj.response.QueryResponse;import org.apache.solr.client.solrj.response.UpdateResponse;import org.apache.solr.common.SolrDocument;import org.apache.solr.common.SolrDocumentList;import org.apache.solr.common.SolrInputDocument;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class SolrUtil {private static final Logger log = LoggerFactory.getLogger(SolrUtil.class);// 声明一个连接solr的对象private static HttpSolrClient client;static {// SolrJ-7.x版本连接Solrclient = new HttpSolrClient.Builder(Constant.SolrConfig.SOLR_URL).build();// SolrJ-5.x版本连接Solr//client = new HttpSolrClient(Constant.SolrConfig.SOLR_URL);}/*** 将Map对象添加到Solr中** @param map Map对象* @return*/public static boolean add(Map map) {Set kSet = map.keySet();SolrInputDocument doc = new SolrInputDocument();for (Object k : kSet) {Object val = map.get(k);if (val != null) {doc.addField(k.toString(), val);}}try {client.add(doc);UpdateResponse resp = client.commit();if (resp.getStatus() == 0) {log.debug("add successfully!");return true;}} catch (Exception e) {log.error(e.getMessage());e.printStackTrace();}log.debug("add failure!");return false;}/*** 通过文档ID删除Solr中的文档** @param id 索引ID* @return*/public static boolean deleteById(String id) {try {client.deleteById(id);UpdateResponse resp = client.commit();if (resp.getStatus() == 0) {log.debug("delete successfully!");return true;}} catch (Exception e) {log.error(e.getMessage());e.printStackTrace();}log.debug("delete failure!");return false;}/*** 通过查询删除Solr中对应的数据集合** @param query 查询条件*/public static boolean deleteByQuery(String query) {try {client.deleteByQuery(query);UpdateResponse resp = client.commit();if (resp.getStatus() == 0) {log.debug("delete successfully!");return true;}} catch (Exception e) {log.error(e.getMessage());e.printStackTrace();}log.debug("delete failure!");return false;}/*** 更新Solr中的文档,Map对象中必须存在id用于定位doc文档** @param map Key<String>代表数据域名称,Value<Object>代表修改值* @return*/public static boolean update(Map<String, Object> map) {try {String id = (String) map.get("id");SolrInputDocument doc = new SolrInputDocument();doc.addField("id", id);for (String key : map.keySet()) {// 数据域Id忽略更新if (!"id".equals(key)) {Map fieldMap = new HashMap();fieldMap.put("set", map.get(key));doc.addField(key, fieldMap);}}client.add(doc);UpdateResponse resp = client.commit();if (resp.getStatus() == 0) {log.debug("update successfully!");return true;}} catch (Exception e) {log.error(e.getMessage());e.printStackTrace();}log.debug("update failure!");return false;}/*** 批量新增或更新记录** @param entities 新增或更新对象列表* @param <T> 泛型* @return* @throws SolrServerException* @throws IOException*/public static <T> boolean batchSaveOrUpdate(List<T> entities) throws SolrServerException, IOException {DocumentObjectBinder binder = new DocumentObjectBinder();int total = entities.size();int count = 0;for (T t : entities) {SolrInputDocument doc = binder.toSolrInputDocument(t);client.add(doc);log.debug("添加数据到索引中,总共要添加 %d 条记录,当前添加第%d条 %n", total, ++count);}client.commit();log.debug("batch Save Or Update successfully!");return true;}/*** 通过泛型获取Solr中的对象集合** @param clz 泛型类对应java.lang.Class* @param query 数据域名称:数据域的值;查询全部*:*;多条件查询 name:Java AND age:20* @param hlFieldsList 高亮显示数据域名称,是List<String>集合* @param page 第几页* @param rows 每页显示记录数* @return*/public static <T> SolrResultInfo<T> query(Class<T> clz, String query, List<String> hlFieldsList, Integer page, Integer rows) {try {// 定义返回自定义数据结构对象SolrResultInfo<T> resultInfo = new SolrResultInfo<T>();SolrQuery q = new SolrQuery();// 查询条件q.set("q", query);// 过滤条件q.set("fl", "*");// 高亮设置(开启)q.setHighlight(true);// 高亮显示字段String hlField = "";for (String s : hlFieldsList) {hlField = hlField + s + ",";}if (hlField.endsWith(",")) {hlField = hlField.substring(0, hlField.length() - 1);}q.set("hl.fl", hlField);// 高亮样式q.setHighlightSimplePre("<font color=\"red\">");q.setHighlightSimplePost("</font>");// 分页设置q.setStart((page - 1) * rows);q.setRows(rows);// 查询响应对象QueryResponse qr = client.query(q);Map<String, Map<String, List<String>>> hlMap = qr.getHighlighting();log.debug(hlMap.toString());// 高亮结果处理SolrDocumentList lst = qr.getResults();List<T> rtn = new ArrayList<T>();Long total = qr.getResults().getNumFound();for (SolrDocument doc : lst) {String id = (String) doc.getFieldValue("id");T t = clz.newInstance();// 获取自定义类所有属性名称Field[] fields = getField(clz);for (Field field : fields) {String fieldName = field.getName();String solrFldName = getSolrFieldName(clz, field);String fObj = getSingleValue(doc.getFieldValue(solrFldName));if (fObj == null) {continue;}if (field.getType() == java.sql.Date.class) {java.util.Date dt = new java.util.Date(fObj);fObj = new java.sql.Date(dt.getTime()).toString();}if (field.getType() == java.sql.Timestamp.class) {java.util.Date dt = new java.util.Date(fObj);fObj = new java.sql.Timestamp(dt.getTime()).toString();}if (field.getType() == java.sql.Time.class) {java.util.Date dt = new java.util.Date(fObj);fObj = new java.sql.Time(dt.getTime()).toString();}// 高亮显示数据形式:Map<ID, Map<FieldName,[MultiValue]>>if (hlFieldsList.contains(fieldName)) {//Map<FieldName,List<MultiValue>>Map<String, List<String>> fldMap = hlMap.get(id);Object hlObj = fldMap.get(fieldName);String hlVal = getSingleValue(hlObj);if (hlVal != null)fObj = hlVal;}if (fObj != null) {BeanUtils.setProperty(t, fieldName, fObj);}}rtn.add(t);}resultInfo.setList(rtn);resultInfo.setTotal(total);return resultInfo;} catch (Exception e) {log.error(e.getMessage());e.printStackTrace();}return null;}/*** 根据Class对象获取此类型的定义属性数据** @param clz class对象* @return*/private static Field[] getField(Class clz) {return clz.getDeclaredFields();}/*** 通过Field对象取得其上定义的注解名称** @param clz* @param fld* @return*/private static String getSolrFieldName(Class clz, Field fld) {org.apache.solr.client.solrj.beans.Field fld2 = fld.getAnnotation(org.apache.solr.client.solrj.beans.Field.class);if (fld2 == null) {return fld.getName();}if (fld2.value().equals("#default")) {return fld.getName();} else {return fld2.value();}}/*** 转化多值域为单值** @param obj* @return*/private static String getSingleValue(Object obj) {if (obj == null) {return null;}String val = obj.toString();if (val.startsWith("[") && val.endsWith("]")) {return val.substring(1, val.length() - 1);}return val;}/*** @author polaris <450733605@qq.com>* Description 查询Solr返回的对象,对象类型为T的集合,还包含Solr中符合条件记录总数* Date 2020-8-20 9:54* Version 1.0.0*/static class SolrResultInfo<T> {private List<T> list = null;private Long total = null;public List<T> getList() {return list;}public void setList(List<T> list) {this.list = list;}public Long getTotal() {return total;}public void setTotal(Long total) {this.total = total;}}}
■ 测试类(SolrUtilTests.java)
import com.lonton.bigdata.pojo.Article;import org.apache.solr.client.solrj.SolrServerException;import org.junit.*;import java.io.IOException;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/*** Description 单元测试(Solr工具类)*/public class SolrUtilTests {/*** BeforeClass:会在所有方法被调用前被执行,* 而且该方法是静态的,所有当测试类被加载后接着就会运行它,* 而且在内存中它只会存在一份实例,它比较适合加载配置文件**/@BeforeClasspublic static void setUpBeforeClass() {System.out.println("this is @BeforeClass ...");}/*** AfterClass:通常用来对资源的清理,如关闭数据库的连接**/@AfterClasspublic static void tearDownAfterClass() {System.out.println("this is @AfterClass ...");}/*** Before:每个测试方法调用前执行一次**/@Beforepublic void setUp() {System.out.println("this is @Before ...");}/*** Before:每个测试方法调用后执行一次**/@Afterpublic void tearDown() {System.out.println("this is @After ...");}@Testpublic void addRecordByMap() {Map<String, Object> map = new HashMap<>();map.put("id", "105");map.put("content_id", 101L);map.put("title", "test我是中国人,打到小日本");map.put("content", "test作为一个中国人,我感到很自豪。");map.put("type", 1);map.put("create_at", 1578912614123L);map.put("publish_at", 1578912614125L);assert SolrUtil.add(map);}@Testpublic void deleteById() {addRecordByMap();assert SolrUtil.deleteById("105");}@Testpublic void deleteByQuery() {addRecordByMap();assert SolrUtil.deleteByQuery("id:105");}@Testpublic void deleteAll() {assert SolrUtil.deleteByQuery("*:*");}@Testpublic void update() {addRecordByMap();Map<String, Object> map = new HashMap<>();map.put("id", "105");map.put("content_id", 999L);map.put("title", "update-test");map.put("content", "update-test");map.put("type", 1);map.put("create_at", 1578912614199L);map.put("publish_at", 1578912614199L);assert SolrUtil.update(map);}@Testpublic void batchSaveOrUpdate() throws IOException, SolrServerException {List<Article> entities = new ArrayList<>();for (int i = 105; i <= 135; i++) {entities.add(new Article(i, i * 10L, "我是中国人,打倒小日本" + i, "作为一个中国人,我感到很自豪。", 1, 1578912614123L, 1578912614123L));}assert SolrUtil.batchSaveOrUpdate(entities);}@Testpublic void query() throws IOException, SolrServerException {batchSaveOrUpdate();List<String> hlFieldsList = new ArrayList<>();hlFieldsList.add("title");hlFieldsList.add("content");int page = 1;int rows = 5;SolrUtil.SolrResultInfo<Article> resultInfo = SolrUtil.query(Article.class, "keywords:中国", hlFieldsList, page, rows);Long total = resultInfo.getTotal();System.out.println("total:" + total);if (total > 0) {for (Article article : resultInfo.getList()) {System.out.println(article);}}}}
附件
参考
博客园:Solr7.4.0的API(Solrj)操作
https://www.cnblogs.com/frankdeng/p/9615856.html
CSDN:Solr操作工具类
https://blog.csdn.net/qixiang_chen/article/details/83076963
