文章目录
全文搜索概述
主要针对文本数据的搜索,全文搜索的目的就是把非结构化的数据变成有结构化的数据进行搜索
文本数据
结构化—数据库的表里面的数据 id name age
半结构化数据 — XML JSON {“id”:1,“name”:“张三”,“age”:50}
非结构化数据 — word PDF (java类库)
集成ElasticSearch全文搜索引擎
纯的java去连接ElasticSearch
spring去连接ElasticSearch
springboot去连接ElasticSearch
Java普通项目集成步骤
- 准备普通Maven项目:导入ElasticSearch依赖
- 连接ElasticSearch:封装成工具类
- 进行文档CRUD
依赖包
<dependencies>
<!--
org.elasticsearch.client 提供的 TransportClient,它是与 Elasticsearch 通信的老版客户端
(注意:TransportClient 在 Elasticsearch 7.x 版本后已被弃用,建议使用 REST High Level Client)
groupId 指定了组织ID(通常是项目的组织或公司)
artifactId 指定了项目的唯一标识符
version 指定了依赖的版本号
-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>6.8.6</version>
</dependency>
<!-- JUnit 是一个流行的 Java 单元测试框架 -->
<!--
groupId 指定了 JUnit 的组织ID
artifactId 指定了 JUnit 的唯一标识符
version 指定了 JUnit 的版本号
scope 指定了该依赖的作用范围,compile 表示该依赖在编译、测试和运行阶段都需要
-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
</dependencies>
ESClientUtil工具类
package org.example.util;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class ESClientUtil {
/**
* 获取 Elasticsearch 的 TransportClient 客户端实例。
* 客户端会连接到配置中的 Elasticsearch 集群。
*
* @return 返回 Elasticsearch 的 TransportClient 客户端实例,如果连接失败则返回 null
*/
public static TransportClient getClient(){
TransportClient client = null;
// 构建 Elasticsearch 设置对象,设置集群名称为 "elasticsearch"
Settings settings = Settings.builder()
.put("cluster.name", "elasticsearch").build();
try {
// 使用提供的设置初始化 PreBuiltTransportClient 对象
client = new PreBuiltTransportClient(settings);
//添加一个传输地址(本地 127.0.0.1 端口 9300)
client.addTransportAddress(new TransportAddress(InetAddress.getByName("127.0.0.1"), 9300));
} catch (UnknownHostException e) {
// 如果在解析主机名时发生异常(比如地址不存在),则打印堆栈跟踪
e.printStackTrace();
}
// 返回创建好的客户端实例,如果发生异常,则返回 null
return client;
}
}
文档CRUD
添加文档
/**
* 添加文档
*/
@Test
public void testAdd() {
//获取客户端对象
TransportClient client = ESClientUtil.getClient();
Map<String,Object> data = new HashMap<>();
data.put("id",1);
data.put("name","zs");
data.put("age",11);
//创建索引
IndexRequestBuilder indexRequestBuilder = client.prepareIndex("pethome", "user", "1");
//获取结果
IndexResponse indexResponse = indexRequestBuilder.setSource(data).get();
System.out.println(indexResponse);
client.close();
}
获取文档
/**
* 获取文档
*/
@Test
public void testObtain() {
// 从ESClientUtil工具类中获取一个TransportClient实例,用于与Elasticsearch进行交互
TransportClient client = ESClientUtil.getClient();
// 构建一个 Get 请求的构造器,用于从指定的索引、类型和文档中检索数据
GetRequestBuilder getRequestBuilder = client.prepareGet("pethome", "user", "1");
try {
// actionGet() 方法会立即返回结果,但也可以将其替换为异步执行的 execute().get()
GetResponse response = getRequestBuilder.execute().actionGet();
// 从响应中获取源数据(即文档内容),并将其转换为字符串进行打印
System.out.println(response.getSourceAsString());
} catch (Exception e) {
// 捕获并打印任何可能发生的异常
e.printStackTrace();
} finally {
// 无论是否发生异常,都关闭 TransportClient 连接
client.close();
}
}
更新文档
/**
* 更新文档
*
* 这个测试方法用于演示如何使用Elasticsearch的TransportClient来更新一个文档。
*/
@Test
public void testUpdate(){
// 从ESClientUtil工具类中获取一个TransportClient实例,用于与Elasticsearch集群进行交互
// 注意:TransportClient在Elasticsearch 7.x版本后已被弃用,推荐使用RestHighLevelClient
TransportClient client = ESClientUtil.getClient();
// 创建一个UpdateRequestBuilder对象,用于构建更新请求
// 第一个参数是索引名,第二个参数是类型名(在Elasticsearch 7.x及以后版本中,类型名通常应为"_doc"),第三个参数是文档ID
UpdateRequestBuilder updateRequestBuilder = client.prepareUpdate("pethome", "user", "10");
// 创建一个Map对象,用于存储要更新的文档数据
Map<String, Object> data = new HashMap<>();
data.put("id", 1); // 假设id字段为整数类型
data.put("name", "zs学习java"); // 更新文档的name字段
data.put("age", 11); // 更新文档的age字段
// 使用setDoc方法设置要更新的文档内容,并立即执行更新操作
// 注意:这将会替换文档中对应字段的现有值,如果字段不存在,则会新增该字段
UpdateResponse updateResponse = updateRequestBuilder.setDoc(data).get();
// 打印更新操作的响应结果
// UpdateResponse包含了更新操作的相关信息,如是否成功、是否强制刷新等
System.out.println(updateResponse);
// 关闭TransportClient连接,释放资源
client.close();
}
批量操作
/**
* 批量添加数据,必须先删除index
* @throws Exception
*/
@Test
public void testBatch() throws Exception {
// 1.获取ES连接
TransportClient client = ESClientUtil.getClient();
// 2.创建批量操作对象
BulkRequestBuilder bulk = client.prepareBulk();
// 3.批量创建文档,放入批量操作对象中
for (int i = 1; i < 10; i++) {
//创建索引
IndexRequestBuilder builder = client.prepareIndex("pethome", "user", i + "").setSource(
XContentFactory.jsonBuilder()
.startObject()
.field("id", i - 1)
.field("name", "我在学习Java!" + i)
.field("age", i - 1)
.field("sex", i%2)
.endObject()
);
BulkResponse result = bulk.add(builder).get();
System.out.println(result.status());
}
// 4.关闭连接
client.close();
}
练习
自定义用户表查询
- name包含:我在学Java
- age在1~12之间
- sex=1
- 需求:name包含:我在学Java和age在1~12之间
需求:name包含:我在学Java
/**
* 需求:name包含:我在源码
*/
@Test
public void testName() {
// 从ESClientUtil工具类中获取一个TransportClient实例,用于与Elasticsearch进行交互
TransportClient client = ESClientUtil.getClient();
// 创建一个SearchRequestBuilder对象,准备进行搜索请求
SearchRequestBuilder searchRequestBuilder = client
// 设置搜索的索引名为"pethome"
.prepareSearch("pethome")
// 设置返回结果从第0条开始(即第一页)
.setFrom(0)
// 注意:在Elasticsearch 7.x及更高版本中,Types已经被弃用,但在6.x中仍然可以使用
.setTypes("user") // 设置要搜索的文档类型为"user"
// 创建一个match查询,用于在"name"字段中搜索包含"我在学Java"的文档
.setQuery(QueryBuilders.matchQuery("name", "我在学Java"))
// 设置返回的文档数量最多为10条
.setSize(10)
// 添加排序条件,按照"age"字段升序排序
.addSort("age", SortOrder.ASC);
try {
// 执行搜索请求,并获取响应
SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
// 获取搜索结果中的命中文档列表
SearchHits hits = searchResponse.getHits();
// 打印命中的总文档数
System.out.println("总条数:"+hits.getTotalHits());
// 遍历命中的文档,并打印它们的源内容(即原始JSON字符串)
for (SearchHit hit : searchResponse.getHits()) {
System.out.println(hit.getSourceAsString());
}
} catch (Exception e) {
// 捕获并打印异常堆栈信息
e.printStackTrace();
} finally {
// 关闭客户端连接,释放资源
client.close();
}
}
需求:age在1~12之间
/**
* 需求:age在1~12之间
*/
@Test
public void testAge() {
// 从ESClientUtil工具类中获取一个TransportClient实例,用于与Elasticsearch进行交互
TransportClient client = ESClientUtil.getClient();
// 创建一个SearchRequestBuilder对象,准备进行搜索请求
SearchRequestBuilder searchRequestBuilder = client.prepareSearch("pethome")
.setTypes("user")
// 用于执行范围查询,搜索年龄字段(age)在1到12之间的文档(包含边界值)
.setQuery(QueryBuilders.rangeQuery("age").from(1).to(12))
.addSort("age",SortOrder.ASC)
.setSize(10); // 设置返回的文档数量
try {
// 执行搜索请求,并获取响应
SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
// 获取搜索结果中的命中文档列表
SearchHits hits = searchResponse.getHits();
// 打印命中的总文档数
System.out.println("总条数:"+hits.getTotalHits());
// 遍历命中的文档,并打印它们的源内容(即原始JSON字符串)
for (SearchHit hit : searchResponse.getHits()) {
System.out.println(hit.getSourceAsString());
}
} catch (Exception e) {
// 捕获并打印异常堆栈信息
e.printStackTrace();
} finally {
// 关闭客户端连接,释放资源
client.close();
}
}
需求:age = 1
/**
* 需求:age = 1
*/
@Test
public void testAgeOne() {
// 从ESClientUtil工具类中获取一个TransportClient实例,用于与Elasticsearch进行交互
TransportClient client = ESClientUtil.getClient();
// 创建一个SearchRequestBuilder对象,准备进行搜索请求
SearchRequestBuilder searchRequestBuilder = client
// 设置搜索的索引名为"pethome"
.prepareSearch("pethome")
// 设置要搜索的文档类型为"user"
.setTypes("user")
// 用于执行精确值查询,搜索年龄字段(age)等于1的文档(精确匹配)
.setQuery(QueryBuilders.termQuery("age",1))
// 设置搜索的起始位置,通常用于分页查询
.setFrom(0)
// 这里设置为10,表示每页返回10条文档
.setSize(10)
// 按照"age"字段升序排序
.addSort("age",SortOrder.ASC);
try {
// 执行搜索请求,并获取响应
SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
// 获取搜索结果中的命中文档列表
SearchHits hits = searchResponse.getHits();
// 打印命中的总文档数
System.out.println("总条数:"+hits.getTotalHits());
// 遍历命中的文档,并打印它们的源内容(即原始JSON字符串)
for (SearchHit hit : searchResponse.getHits()) {
System.out.println(hit.getSourceAsString());
}
} catch (Exception e) {
// 捕获并打印异常堆栈信息
e.printStackTrace();
} finally {
// 关闭客户端连接,释放资源
client.close();
}
}
需求:name包含:我在学Java和age在1~12之间
/**
* 需求:name包含:我在学Java和age在1~12之间
*/
@Test
public void testNameAndAge() {
// 从ESClientUtil工具类中获取一个TransportClient实例,用于与Elasticsearch进行交互
TransportClient client = ESClientUtil.getClient();
// 创建一个SearchRequestBuilder对象,准备进行搜索请求
SearchRequestBuilder searchRequestBuilder = client
// 设置搜索的索引名为"pethome"
.prepareSearch("pethome")
// 设置要搜索的文档类型为"user"
.setTypes("user")
// 创建一个复合查询(boolQuery),需要同时满足以下条件
.setQuery(QueryBuilders.boolQuery()
// 用于执行范围查询,搜索年龄字段(age)在1到12之间的文档(包含边界值)
.must(QueryBuilders.rangeQuery("age").from(1).to(12))
// 执行全文搜索,搜索名字字段(name)中包含"我在学Java"的文档
.must(QueryBuilders.matchQuery("name", "我在学Java")))
// 添加排序条件,按照"age"字段升序排序
.addSort("age", SortOrder.ASC)
// 设置返回的文档数量最多为10条
.setSize(10);
try {
// 执行搜索请求,并获取响应
SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
// 获取搜索结果中的命中文档列表
SearchHits hits = searchResponse.getHits();
// 打印命中的总文档数
System.out.println("总条数:"+hits.getTotalHits());
// 遍历命中的文档,并打印它们的源内容(即原始JSON字符串)
for (SearchHit hit : searchResponse.getHits()) {
System.out.println(hit.getSourceAsString());
}
} catch (Exception e) {
// 捕获并打印异常堆栈信息
e.printStackTrace();
} finally {
// 关闭客户端连接,释放资源
client.close();
}
}
三种不同类型的查询
matchQuery
用于执行全文搜索,它会分析提供的查询字符串,并在倒排索引中查找匹配的项。这种查询通常用于文本字段,它会考虑字段的分析器设置。
QueryBuilders.matchQuery("name", "我在学Java")
rangeQuery
用于执行范围查询,它可以指定一个字段的值的范围。这对于数值字段和日期字段特别有用。
// 搜索年龄字段(age)在1到12之间的文档(包含边界值)
QueryBuilders.rangeQuery("age").from(1).to(12)
termQuery
用于执行精确值查询,它不会分析查询字符串,而是直接查找与给定值完全匹配的项。这通常用于关键字字段或不需要分析的数值字段。
// 搜索年龄字段(age)等于1的文档(精确匹配)
// 注意:对于文本字段,由于它们通常会被分析,所以termQuery可能不会按预期工作
QueryBuilders.termQuery("age", 1)