7.Java中使用Solr,历史版本(7.0.0之后、5.0.0~6.6.6、4.10.4之前)

目录


Solr专栏目录(点击进入…)



Java中使用Solr,历史版本(7.0.0之后、5.0.0~6.6.6、4.10.4之前)

导入依赖

<dependency>
	<groupId>org.apache.solr</groupId>
	<artifactId>solr-solrj</artifactId>
	<version>8.5.1</version>
</dependency>
<!--日志的包, solrj执行需要一个日志包 -->
<dependency>
	<groupId>commons-logging</groupId>
	<artifactId>commons-logging</artifactId>
	<version>1.2</version>
</dependency>

新版本(7.0.0之后)

Solr的所有请求均由SolrClient发送,具有灵活性。SolrClient是SolrJ核心。负责连接到Solr并与之通信的工作,并且是大多数用户配置的发生地。请求以的形式发送,并以形式SolrRequests返回SolrResponses

注意:新版本Solr获取SolrClient的方式也和之前旧版本有所不同。Solr 6.5开始不推荐直接使用HttpSolrClient的构造方法创建SolrClient

从7.0.0开始删除了HttpSolrClient创建客户端的构造方法,使用内部类Builder构建SolrClient

SolrClients类型
SolrClient有一些具体的实现,每个实现都针对不同的使用模式或弹性模型

Client类型描述
HttpSolrClient面向以查询为中心的工作负载,尽管它也是一个很好的通用客户端。直接与单个Solr节点通信
Http2SolrClient利用HTTP/2的异步,非阻塞和通用客户端。此类是实验性的,因此它的API可能会在次要版本的SolrJ中更改或删除
LBHttpSolrClient在整个Solr节点列表之间平衡请求负载。根据节点运行状况调整“服务中”节点的列表
LBHttp2SolrClient就像LBHttpSolrClient但Http2SolrClient改用。此类是实验性的,因此它的API可能会在次要版本的SolrJ中更改或删除
CloudSolrClient旨在与SolrCloud部署进行通信。使用已经记录的ZooKeeper状态来发现请求并将其路由到健康的Solr节点
ConcurrentUpdateSolrClient面向以索引为中心的工作负载。在将较大的批次发送到Solr之前,在内部缓冲文档
ConcurrentUpdateSolrClient就像ConcurrentUpdateSolrClient但Http2SolrClient改用。此类是实验性的,因此它的API可能会在次要版本的SolrJ中更改或删除

基本网址

大多数SolrClient实现(CloudSolrClient和Http2SolrClient除外)都要求用户指定一个或多个Solr基本URL,然后客户端将其用于将HTTP请求发送到Solr。从那时起,用户在其提供的基本URL上包括的路径会影响所创建客户端的行为

(1)具有指向特定核心或集合路径的URL

(例如:http://hostname:8983/solr/core1)。如果在基本URL中指定了核心或集合,则不需要对该客户端进行的后续请求来重新指定受影响的集合。但是,客户端仅限于将请求发送到该核心/集合,而不能将请求发送到任何其他请求

SolrClient client = new HttpSolrClient.Builder("http://my-solr-server:8983/solr/core1").build();
QueryResponse response = client.query(new SolrQuery("*:*"));

效果:不可以选择其他内核查询,但是在执行请求时不需要再声明指定内核

(2)指向根Solr路径的URL

(例如:http://hostname:8983/solr)。如果在基本URL中未指定核心或集合,则可以对任何核心/集合进行请求,但是必须在所有请求上指定受影响的核心/集合

SolrClient client = new HttpSolrClient.Builder("http://my-solr-server:8983/solr").build();
QueryResponse response = client.query("core1", new SolrQuery("*:*"));

效果:更加灵活的运用,可以向任意内核发送请求,但是请求必须声明内核名

一般来说,如果SolrClient仅用于单个核心/集合,则在路径中包括该实体是最方便的。如果需要更大的灵活性,则应排除集合/核心


创建HttpSolrClient

//solr4创建方式
SolrServer solrServer = new HttpSolrServer("http://localhost:8983/solr/core");  

//solr5创建方式,在url中指定core名称
HttpSolrClient solrServer=new HttpSolrClient("http://localhost:8983/solr/core");

//solr7创建方式,在url中指定core名称
HttpSolrClient solrServer = new HttpSolrClient
.Builder("http://localhost:8983/solr/core").build();

final String solrUrl = "http://localhost:8983/solr/core";
//创建solrClient同时指定超时时间,不指定走默认配置
HttpSolrClient build = new HttpSolrClient.Builder(solrUrl)
		                .withConnectionTimeout(10000)
		                .withSocketTimeout(60000)
		                .build();		
<!--整合solr服务器与客户端信息 -->
<context:property-placeholder location="classpath:solr.properties" />

<!-- Spring配置solrJ -->
<bean id="builder" class="org.apache.solr.client.solrj.impl.HttpSolrClient.Builder">
	<!-- solrJ内核url -->
	<constructor-arg name="baseSolrUrl" value="${solr.url}"/>
</bean>

<bean id="httpSolrClient" class="org.apache.solr.client.solrj.impl.HttpSolrClient">
	<constructor-arg name="builder" ref="builder"/>
</bean>

SolrJ的增删改查(单机版API操作)

1.创建索引

(1)指定id单条创建索引

String solrUrl = "http://node21:8080/solr/new_core";
HttpSolrClient solrClient = new HttpSolrClient.Builder(solrUrl).build();
// 创建索引文档对象
SolrInputDocument doc = new SolrInputDocument();
// 第一个参数:域的名称,域的名称必须是在schema.xml中定义的
// 第二个参数:域的值,注意:id的域不能少
doc.addField("id", "1");
doc.addField("name", "红豆");
doc.addField("price", "1.2");
// 3.将文档写入索引库中
solrClient.add(doc);
solrClient.commit();

(2)批量创建索引

String solrUrl = "http://node21:8080/solr/new_core";
HttpSolrClient solrClient = new HttpSolrClient.Builder(solrUrl).build();
// 创建索引文档对象
SolrInputDocument doc1 = new SolrInputDocument();
doc1.addField("id", "2");
doc1.addField("name", "绿豆");
doc1.addField("price", 1.8);

SolrInputDocument doc2 = new SolrInputDocument();
doc2.addField("id", "3");
doc2.addField("name", "黑豆");
doc2.addField("price", 2.6);
List<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
docs.add(doc1);
docs.add(doc2);
// 3.将文档写入索引库中
solrClient.add(docs);
solrClient.commit();

2.更新索引

String solrUrl = "http://node21:8080/solr/new_core";
HttpSolrClient solrClient = new HttpSolrClient.Builder(solrUrl).build();
// 创建索引文档对象
SolrInputDocument doc = new SolrInputDocument();
// 把红豆价格修改为1.5
doc.addField("id", "1");
doc.addField("name", "红豆");
doc.addField("price", "1.5");
// 3.将文档写入索引库中
solrClient.add(doc);
solrClient.commit();
// 提交
solrClient.commit();

3.删除索引

(1)单一条件删除

String solrUrl = "http://node21:8080/solr/new_core";
HttpSolrClient solrClient = new HttpSolrClient.Builder(solrUrl).build();
// 全删
// solrClient.deleteByQuery("*:*");
// 模糊匹配删除(带有分词效果的删除)
solrClient.deleteByQuery("name:红");
// 指定id删除
// solrClient.deleteById("1");
solrClient.commit();

(2)批量条件删除

String solrUrl = "http://node21:8080/solr/new_core";
HttpSolrClient solrClient = new HttpSolrClient.Builder(solrUrl).build();
// 通过id删除
ArrayList<String> ids = new ArrayList<String>();
ids.add("2");
ids.add("3");
solrClient.deleteById(ids);
// [3]提交
solrClient.commit();
// [4]关闭资源
solrClient.close();

4.查询索引(重点)

SolrClient有很多query()方法可以从Solr获取结果。这些方法中的每一个都采用SolrParams一个对象,该对象封装了任意查询参数。每个方法都输出一个QueryResponse包装器,该包装器可用于访问结果文档和其他相关的元数据

SolrParams有一个SolrQuery子类,它提供了一些方便的方法,可以大大简化查询的创建

1.基本查询
(1)匹配查询
String solrUrl = "http://localhost:8983/solr/mycore";
HttpSolrClient solrClient = new HttpSolrClient.Builder(solrUrl).build();
// 创建搜索对象
SolrQuery query = new SolrQuery();
// 设置搜索条件
query.set("q", "*:*");
// 设置每页显示多少条
query.setRows(2);

// 发起搜索请求
QueryResponse response = solrClient.query(query);
// 查询结果
SolrDocumentList docs = response.getResults();
// 查询结果总数
long cnt = docs.getNumFound();
System.out.println("总条数为" + cnt + "条");
for (SolrDocument doc : docs) {
	System.out.println("id:" + doc.get("id") + ",name:" + doc.get("name"));
}
solrClient.close();
(2)条件过滤查询
String solrUrl = "http://node21:8080/solr/new_core";
HttpSolrClient solrClient = new HttpSolrClient.Builder(solrUrl).build();
// 2 封装查询参数
Map<String, String> queryParamMap = new HashMap<String, String>();
queryParamMap.put("q", "*:*");
// 3 添加到SolrParams对象,SolrParams 有一个 SolrQuery 子类,提供了一些方法极大地简化了查询操作
MapSolrParams queryParams = new MapSolrParams(queryParamMap);
// 4 执行查询返回QueryResponse
QueryResponse response = solrClient.query(queryParams);
// 5 获取doc文档
SolrDocumentList docs = response.getResults();
// 查询结果总数
long cnt = docs.getNumFound();
System.out.println("总条数为" + cnt + "条");
// [6]内容遍历
for (SolrDocument doc : docs) {
	System.out.println("id:" + doc.get("id") + ",name:" + doc.get("name"));
}
solrClient.close();

2.复杂查询
服务对象
public void query(SolrQuery query) throws Exception {
	// 获取连接
	String solrUrl = "http://127.0.0.1:8983/solr/core1";
	// 创建solrClient同时指定超时时间,不指定走默认配置
	HttpSolrClient client = new HttpSolrClient.Builder(solrUrl)
		.withConnectionTimeout(10000)
		.withSocketTimeout(60000)
		.build();
	// 创建Solr的查询对象
	QueryResponse response = client.query(query);
	// 文档的集合
	SolrDocumentList documentList = response.getResults();
	for (SolrDocument document : documentList) {
		String id = document.get("id").toString();
		String title = document.get("title").toString();
		System.out.println("id:" + id + ";title:" + title);
	}
}
(1)词条查询
SolrQuery query = new SolrQuery("title:钱");
query(query);
(2)通配符查询

匹配0到多个字符 ?:匹配1个字符

SolrQuery query = new SolrQuery("title:selin*");
query(query);
(3)模糊查询
/**
 * 在关键字之后添加~,表示进行模糊查询。最大编辑次数:通过新增、修改、删除可以匹配正确的词条的次数,默认为2~后的数据,表示最大的编辑次数
 */
SolrQuery query = new SolrQuery("title:selinaq~1");
query(query);
(4)范围查找查询
// SolrQuery query = new SolrQuery("id:[20 TO 50]");
SolrQuery query = new SolrQuery("publishTime:{2001-01-01T12:00:00Z TO 2019-01-01T12:00:00Z}");
query(query);
(5)组合
//AND OR NOT
SolrQuery query = new SolrQuery(" title:xxx or inrot:xxx");
query(query);

.

3.高级使用
(1)solr的排序
SolrQuery solrQuery = new SolrQuery("*:*");
solrQuery.setSort("id", SolrQuery.ORDER.asc);
query(solrQuery);
(2)solr的分页
// 当前页
int page = 2;
// 每页条数
int pageSize = 3;

SolrQuery solrQuery = new SolrQuery("*:*");
// 排序
solrQuery.setSort("id", SolrQuery.ORDER.asc);
// 分页
solrQuery.setStart((page - 1) * pageSize);
solrQuery.setRows(pageSize);
query(solrQuery);
(3)solr 的高亮
int page = 1;  //当前页
int pageSize = 3;  //每页条数

SolrQuery solrQuery = new SolrQuery("content:lucene");
// 排序
solrQuery.setSort("id", SolrQuery.ORDER.asc);
// 分页
solrQuery.setStart((page - 1) * pageSize);
solrQuery.setRows(pageSize);

solrQuery.setHighlight(true);  // 开启了高亮
solrQuery.addHighlightField("content"); 
//使用add方法来设置高亮字段,说明高亮字段可以有多个
solrQuery.addHighlightField("title");
solrQuery.setHighlightSimplePre("<font color='red'>");
solrQuery.setHighlightSimplePost("</font>");

// 2. 执行查询
QueryResponse response = client.query(solrQuery);
/*
 * 最外层的map: key: 文档的id value: 文档的高亮内容 内层的map: key: 高亮的字段 value: 这个字段的高亮内容
 * list集合: 高亮内容, 而且集合中一般只有一个数据, 除非高亮的字段是一个多值的字段,并且设置高亮的最大分片数大于1
 */
Map<String, Map<String, List<String>>> map = response.getHighlighting();

for (String docId : map.keySet()) {
	Map<String, List<String>> listMap = map.get(docId);
	for (String filed : listMap.keySet()) {
		List<String> list = listMap.get(filed);
		System.out.println(list.get(0) + "    " + list.size());
	}
}

Java对象绑定

尽管SolrJ提供的UpdateResponse和QueryResponse接口非常有用,但是使用特定于域的对象通常更方便,这些对象可以被您的应用程序更容易地理解。值得庆幸的是,SolrJ通过隐式地将文档与任何已特别标记为@Field注释的类之间来回转换来支持此操作

可以使用@Field注释将Java对象中的每个实例变量映射到相应的Solr字段。Solr字段默认情况下共享带注释的变量的名称,但是,可以通过为注释提供显式字段名称来覆盖此名称。

使用@FieId注解字段
public class Product {
	@Field
	private String id;
	@Field
	private String p_name;
	//省略getter/setter方法、构造方法
}
1.通过对象创建索引
// [1]获取连接
String solrUrl = "http://127.0.0.1:8983/solr/core1";
// [2]创建solrClient同时指定超时时间,不指定走默认配置
HttpSolrClient client = new HttpSolrClient.Builder(solrUrl)
	.withConnectionTimeout(10000)
	.withSocketTimeout(60000)
	.build();
// [3]创建对象
Product product = new Product();
product.setId("30000");
product.setP_name("测试商品名称");
// [4]添加对象
UpdateResponse response = client.addBean(product);
// [5]提交操作
client.commit();
// [6]关闭资源
client.close();
2.通过deleteByQuery删除索引
String solrUrl = "http://127.0.0.1:8080/solr/core1";
//创建solrClient同时指定超时时间,不指定走默认配置
HttpSolrClient client = new HttpSolrClient.Builder(solrUrl)
                .withConnectionTimeout(10000)
                .withSocketTimeout(60000)
                .build();
//[2]执行删除
client.deleteByQuery("id:100");
//[3]提交操作
client.commit();
//[4]关闭资源
client.close();  
3.通过对象索引查询
String solrUrl = "http://127.0.0.1:8080/solr/core1";
// 创建solrClient同时指定超时时间,不指定走默认配置
HttpSolrClient client = new HttpSolrClient.Builder(solrUrl)
		.withConnectionTimeout(10000)
		.withSocketTimeout(60000)
		.build();
// [2]创建SolrQuery对象
SolrQuery query = new SolrQuery("*:*");
// 添加回显的内容
query.addField("id");
query.addField("p_name");
query.setRows(200);// 设置每页显示多少条

// [3]执行查询返回QueryResponse
QueryResponse response = client.query(query);
// [4]获取doc文档
List<Product> products = response.getBeans(Product.class);
// [5]遍历
for (Product product : products) {
	System.out.println("id:" + product.getId()+"p_name:" + product.getP_name());
}
client.close(); // 关闭资源

老版本(5.0.0~6.6.6)

5版本还能使用过时的HttpSolrServer。6版本就不复存在了

在solr 5系之后跟solr4最大的区别是被发布成了一个独立的应用。而不再需要tomcat等容器。在其内部集成了jetty服务器,他可以通过bin目录的脚本直接运行启动。solr5有两种运行模式,独立模式和云模式,独立模式是以core来管理,云模式是以collection来管理

使用的是实例化HttpSolrClient来操作Solr索引库

new HttpSolrClient("http://127.0.0.1:8983/solr/core1");

老旧版本(4.10.4之前)

4.10.4为最后一个版本

(1)新增索引

1.原生方式
// 1. 创建solr的服务对象(发送请求, 获取数据)
SolrServer solrServer = new HttpSolrServer("http://localhost:8983/solr/core");
// 2. 添加索引	
/* name的字段名必须存在,配置在schema.xml */
List<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();

SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", "2");
doc.addField("title", "双十一来了");
doc.addField("content", "又到了卖肾的季节了");
docs.add(doc);
SolrInputDocument doc1 = new SolrInputDocument();
doc1.addField("id", "3");
doc1.addField("title", "剁手节来了");
doc1.addField("content", "今天你剁手了吗?");
docs.add(doc1);

solrServer.add(docs);
// 3. 提交数据
solrServer.commit();
2.一次写入多条索引
// 1. 创建solrServer对象
SolrServer solrServer = new HttpSolrServer("http://localhost:8983/solr/core");
// 2. 设置多条数据
List<SolrInputDocument> docs = new ArrayList<>();
for (int i = 0; i < 10; i++) {
	// 2.1 创建一个document
	SolrInputDocument document = new SolrInputDocument();
	document.addField("id", i);
	document.addField("content", "solr是一个独立的企业级搜索应用服务器, 可以通过http请求访问这个服务器, 获取或者写入对应的内容, 其底层是Lucene " + i);
	document.addField("title", "solr的简介");
	// 2.2 将document添加到集合中
	docs.add(document);
}
// 3. 写入索引
solrServer.add(docs);
// 4. 提交索引
solrServer.commit();
3.使用JavaBean来添加索引数据
// 1. 创建 solr的服务对象
SolrServer solrServer = new HttpSolrServer("http://localhost:8983/solr/core");
// 2. 添加文档数据
News news = new News("3", "Ella","http://ent.163.com/18/1107/10/E00KM09000038FO9.html");
solrServer.addBean(news);
// 使用addBeans来添加多条数据
// 3. 提交数据
solrServer.commit();

(2)删除索引库

// 1. 创建solr的服务对象
SolrServer solrServer = new HttpSolrServer("http://localhost:8983/solr/core");
// 2. 执行删除
// solrServer.deleteByQuery("*:*"); 删除全部的数据
solrServer.deleteById("1"); // 删除id为1的数据
// 3. 提交数据
solrServer.commit();

(3)查询索引库

1.基本查询
(1)查询全部
//1. 创建 solrServer对象
SolrServer solrServer = new HttpSolrServer("http://localhost:8983/solr/core");
//2. 执行查询
//SolrQuery : solr的查询对象
SolrQuery solrQuery = new SolrQuery("*:*");
QueryResponse response = solrServer.query(solrQuery);
//3. 获取数据
SolrDocumentList documentList = response.getResults();
for (SolrDocument document : documentList) {
	String id = (String) document.get("id");
	String title = (String) document.get("title");
	String content = (String) document.get("content");
	String url = (String) document.get("url");
	System.out.println("id "+id+" title"+title+" content"+content+" url"+url);
}
(2)查询对象
//1. 创建 solrServer对象
SolrServer solrServer = new HttpSolrServer("http://localhost:8983/solr/core");
//2. 执行查询
//SolrQuery : solr的查询对象
SolrQuery solrQuery = new SolrQuery("*:*");
QueryResponse response = solrServer.query(solrQuery);
//3. 获取数据 : 此处有可能会出现转换类型异常的错误:
List<News> newsList = response.getBeans(News.class);
for (News news : newsList) {
	System.out.println(news.getId()+" "+news.getTitle());
}

2.复杂查询
服务对象
public void query(SolrQuery query) throws Exception {
	// 创建SolrServer服务对象
	SolrServer server = new HttpSolrServer("http://localhost:8983/solr/core");
	// 创建solr的查询对象
	QueryResponse response = server.query(query);
	// 文档的集合
	SolrDocumentList documentList = response.getResults();
	for (SolrDocument document : documentList) {
		String id = document.get("id").toString();
		String title = document.get("title").toString();
		System.out.println("id:" + id + ";title:" + title);
	}
}
(1)词条查询
SolrQuery query = new SolrQuery("title:钱");
query(query);
(2)通配符查询

匹配0到多个字符 ?:匹配1个字符

SolrQuery query = new SolrQuery("title:selin*");
query(query);
(3)模糊查询
/*
* 在关键字之后添加~,表示进行模糊查询 最大编辑次数:通过新增,修改,删除可以匹配正确的词条的次数,默认为2 ~后的数据,表示最大的编辑次数
*/
SolrQuery query = new SolrQuery("title:selinaq~1");
query(query);
(4)范围查找查询
// SolrQuery query = new SolrQuery("id:[20 TO 50]");
SolrQuery query = new SolrQuery("publishTime:{2001-01-01T12:00:00Z TO 2019-01-01T12:00:00Z}");
query(query);
(5)组合
//AND OR NOT
SolrQuery query = new SolrQuery("id:[20 TO 50]");
SolrQuery query = new SolrQuery(" title:xxx or inrot:xxx");
query(query);

3.高级使用
(1)solr的排序
SolrQuery solrQuery = new SolrQuery("*:*");
solrQuery.setSort("id", SolrQuery.ORDER.asc);
query(solrQuery);
(2)solr的分页
int page = 2; // 当前页
int pageSize = 3;// 每页条数

SolrQuery solrQuery = new SolrQuery("*:*");
// 排序
solrQuery.setSort("id", SolrQuery.ORDER.asc);
// 分页
solrQuery.setStart((page - 1) * pageSize);
solrQuery.setRows(pageSize);
query(solrQuery);
(3)solr 的高亮
// 创建solr的服务对象
SolrQuery solrServer = new HttpSolrServer("http://localhost:8983/solr/core");
int page = 1;  //当前页
int pageSize = 3;  //每页条数

SolrQuery solrQuery = new SolrQuery("content:lucene");
// 排序
solrQuery.setSort("id", SolrQuery.ORDER.asc);
// 分页
solrQuery.setStart((page - 1) * pageSize);
solrQuery.setRows(pageSize);

// 高亮:
solrQuery.setHighlight(true); //开启了高亮
solrQuery.addHighlightField("content"); 
//使用add方法来设置高亮字段, 说明高亮字段可以有多个
solrQuery.addHighlightField("title");
solrQuery.setHighlightSimplePre("<font color='red'>");
solrQuery.setHighlightSimplePost("</font>");

// 2. 执行查询
QueryResponse response = solrServer.query(solrQuery);
/*
* 最外层的map: key: 文档的id value: 文档的高亮内容 内层的map: key: 高亮的字段 value: 这个字段的高亮内容
* list集合: 高亮内容, 而且集合中一般只有一个数据, 除非高亮的字段是一个多值的字段,并且设置高亮的最大分片数大于1
*/
Map<String, Map<String, List<String>>> map = response.getHighlighting();

for (String docId : map.keySet()) {
	Map<String, List<String>> listMap = map.get(docId);
	for (String filed : listMap.keySet()) {
		List<String> list = listMap.get(filed);
		System.out.println(list.get(0) + "    " + list.size());
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未禾

您的支持是我最宝贵的财富!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值