简介
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名称:core1
HttpSolrClient solrClient = new HttpSolrClient(solrUrl);
// solr7创建方式,在url中指定core名称:core1
HttpSolrClient 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不给值将自动生成UUID
doc.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不给值将自动生成UUID
doc.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
@NoArgsConstructor
public 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;
@Override
public 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=205
solrQuery.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版本连接Solr
client = 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:会在所有方法被调用前被执行,
* 而且该方法是静态的,所有当测试类被加载后接着就会运行它,
* 而且在内存中它只会存在一份实例,它比较适合加载配置文件
**/
@BeforeClass
public static void setUpBeforeClass() {
System.out.println("this is @BeforeClass ...");
}
/**
* AfterClass:通常用来对资源的清理,如关闭数据库的连接
**/
@AfterClass
public static void tearDownAfterClass() {
System.out.println("this is @AfterClass ...");
}
/**
* Before:每个测试方法调用前执行一次
**/
@Before
public void setUp() {
System.out.println("this is @Before ...");
}
/**
* Before:每个测试方法调用后执行一次
**/
@After
public void tearDown() {
System.out.println("this is @After ...");
}
@Test
public 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);
}
@Test
public void deleteById() {
addRecordByMap();
assert SolrUtil.deleteById("105");
}
@Test
public void deleteByQuery() {
addRecordByMap();
assert SolrUtil.deleteByQuery("id:105");
}
@Test
public void deleteAll() {
assert SolrUtil.deleteByQuery("*:*");
}
@Test
public 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);
}
@Test
public 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);
}
@Test
public 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