JavaAPI操作ES服务器
创建空项目,添加modles(maven管理),导入依赖,进行操作ES。
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>5.6.8</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>5.6.8</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.24</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
- 创建索引
@Test
//1.创建索引
public void test1() throws Exception{
// 创建Client连接对象,告知连接的集群的名称和通信ip和端口
Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();
TransportClient client = new PreBuiltTransportClient(settings)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9301))
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9302))
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9303));
//创建名称为demo1的索引
client.admin().indices().prepareCreate("demo1").get();
//释放资源
client.close();
}
- 设置mapping映射(json中第一个数据为type名称,第二个properties为type中的字段)
@Test
//2.创建映射
public void test3() throws Exception {
// 创建Client连接对象
Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();
TransportClient client = new PreBuiltTransportClient(settings)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9301))
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9302))
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9303));
// 添加映射
/**
* 格式:
* "mappings" : {
"article" : {
"dynamic" : "false",
"properties" : {
"id" : { "type" : "string" },
"content" : { "type" : "string" },
"author" : { "type" : "string" }
}
}
}
*/
XContentBuilder builder = XContentFactory.jsonBuilder()
.startObject()
.startObject("hello1")
.startObject("properties")
.startObject("id")
.field("type", "integer")
.field("store", true)
.endObject()
.startObject("title")
.field("type", "string")
.field("store", true)
.field("analyzer", "ik_smart")
.endObject()
.startObject("content")
.field("type", "string")
.field("store", true)
.field("analyzer", "ik_smart")
.endObject()
.endObject()
.endObject()
.endObject();
// 创建映射
client.admin().indices()
.preparePutMapping("demo1")//指定索引名
.setType("hello1")//设置type名,需要和builder保持一致
.setSource(builder)//设置mapping内容
.get();//执行操作
//释放资源
client.close();
}
- 添加文档
1)创建Article实体
public class Article {
private Integer id;
private String title;
private String content;
getter/setter...
}
2)添加fastjson坐标
<!--json转换工具-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>
@Test
//3.创建文档(通过实体转json)
public void test5() throws Exception {
// 创建Client连接对象
Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();
TransportClient client = new PreBuiltTransportClient(settings)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9301));
// 描述json 数据
//{id:xxx, title:xxx, content:xxx}
Hello hello = new Hello();
hello.setId(2);
hello.setTitle("搜索工作其实很快乐");
hello.setContent("我们希望我们的搜索解决方案要快,我们希望有一个零配置和一个完全免费的搜索模式,我们希望能够简单地使用JSON通过HTTP的索引数据,我们希望我们的搜索服务器始终可用,我们希望能够一台开始并扩展到数百,我们要实时搜索,我们要简单的多租户,我们希望建立一个云的解决方案。Elasticsearch旨在解决所有这些问题和更多的问题。");
//将对象装换为json
Object o = JSON.toJSON(hello);
String s = o.toString();
System.out.println(o);
// 建立文档,此处设置对象的id为_id
client.prepareIndex("demo1", "hello1", hello.getId().toString())
.setSource(s.getBytes(), XContentType.JSON)
.get();
//释放资源
client.close();
}
查询:通过QueryBuilder来设置查询方式和查询的条件
抽取连接es服务器获取client客户端的操作
private TransportClient client;
@Before
public void creatConn(){
//1、创建es客户端连接对象
Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();
try {
client = new PreBuiltTransportClient(settings)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9301));
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
- 根据_id查询
@Test
//4.2根据_id进行查询,id可以为多个
public void testQueryId() throws Exception{
//2、设置搜索条件
QueryBuilder queryBuilder=QueryBuilders.idsQuery().addIds("1").addIds("2");
SearchResponse searchResponse = client.prepareSearch("demo1")
.setTypes("hello1")
.setQuery(queryBuilder).get();
//3、遍历搜索结果数据
SearchHits hits = searchResponse.getHits(); // 获取命中次数,查询结果有多少对象
System.out.println("查询结果有:" + hits.getTotalHits() + "条");
Iterator<SearchHit> iterator = hits.iterator();
while (iterator.hasNext()) {
SearchHit searchHit = iterator.next(); // 每个查询对象
System.out.println(searchHit.getSourceAsString()); // 获取字符串格式打印
System.out.println("title:" + searchHit.getSource().get("title"));
}
//4、释放资源
client.close();
}
- 根据term查询
@Test
//4.1根据关键字进行查询term
public void testTermQuery() throws Exception{
//1、创建es客户端连接对象
Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();
TransportClient client = new PreBuiltTransportClient(settings)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9301));
//2、设置搜索条件
QueryBuilder queryBuilder = QueryBuilders.termQuery("content", "搜索");
SearchResponse searchResponse = client.prepareSearch("demo1")
.setTypes("hello1")
.setQuery(queryBuilder).get();
//3、遍历搜索结果数据
SearchHits hits = searchResponse.getHits(); // 获取命中次数,查询结果有多少对象
System.out.println("查询结果有:" + hits.getTotalHits() + "条");
Iterator<SearchHit> iterator = hits.iterator();
while (iterator.hasNext()) {
SearchHit searchHit = iterator.next(); // 每个查询对象
System.out.println(searchHit.getSourceAsString()); // 获取字符串格式打印
System.out.println("title:" + searchHit.getSource().get("title"));
}
//4、释放资源
client.close();
}
- 根据queryString查询:多条件查询先拆词后对词进行搜索满足其中一个即可
queryString 多条件查询
•会对查询条件进行分词。
•然后将分词后的查询条件和词条进行等值匹配
•默认取并集(OR)
•可以指定多个查询字段
@Test
//4.3根据字符串进行搜索。拆词进行匹配。
public void testStringQuery() throws Exception{
//1、创建es客户端连接对象
Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();
TransportClient client = new PreBuiltTransportClient(settings)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9301));
//2、设置搜索条件
QueryBuilder queryBuilder=QueryBuilders.queryStringQuery("搜索");//分词器拆成了搜和索进行查找
//quertyBuilder.field("mapping列名").field("mapping列名")用来指定要搜索的列
SearchResponse searchResponse = client.prepareSearch("demo1")
.setTypes("hello1")
.setQuery(queryBuilder).get();
//3、遍历搜索结果数据
SearchHits hits = searchResponse.getHits(); // 获取命中次数,查询结果有多少对象
System.out.println("查询结果有:" + hits.getTotalHits() + "条");
Iterator<SearchHit> iterator = hits.iterator();
while (iterator.hasNext()) {
SearchHit searchHit = iterator.next(); // 每个查询对象
System.out.println(searchHit.getSourceAsString()); // 获取字符串格式打印
System.out.println("title:" + searchHit.getSource().get("title"));
}
//4、释放资源
client.close();
}
- 查询分页
@Test
//5.1创建文档(通过实体转json)
public void insertMany() throws Exception {
for (int i = 0; i < 50; i++) {
//描述json 数据
//{id:xxx, title:xxx, content:xxx}
Hello hello = new Hello();
hello.setId(i);
hello.setTitle("分页数据搜加索"+i);
hello.setContent("分页内容搜"+i);
//将对象装换为json
Object o = JSON.toJSON(hello);
String s = o.toString();
System.out.println(o);
// 建立文档,此处设置对象的id为_id
client.prepareIndex("demo1", "hello1", hello.getId().toString())
.setSource(s.getBytes(), XContentType.JSON)
.get();
}
//释放资源
client.close();
}
@Test
//5.2分页查询数据
public void testStringQuery1() throws Exception{
//1、创建es客户端连接对象
Settings settings = Settings.builder().put("cluster.name", "my-elasticsearch").build();
TransportClient client = new PreBuiltTransportClient(settings)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9301));
//2、设置搜索条件
QueryBuilder queryBuilder=QueryBuilders.queryStringQuery("搜索");//分词器拆成了搜和索进行查找
SearchResponse searchResponse = client.prepareSearch("demo1")
.setTypes("hello1")
.setQuery(queryBuilder)
//不设置默认展示10条数据
.setFrom(0)
.setSize(5)
.get();
//3、遍历搜索结果数据
SearchHits hits = searchResponse.getHits(); // 获取命中次数,查询结果有多少对象
System.out.println("查询结果有:" + hits.getTotalHits() + "条");
Iterator<SearchHit> iterator = hits.iterator();
while (iterator.hasNext()) {
SearchHit searchHit = iterator.next(); // 每个查询对象
System.out.println(searchHit.getSourceAsString()); // 获取字符串格式打印
System.out.println("title:" + searchHit.getSource().get("title"));
}
//4、释放资源
client.close();
}
- 查询结果高亮显示
实现原理在关键词的前后加上了一个h5标签来进行高亮显示
在进行关键字搜索时,搜索出的内容中的关键字会显示不同的颜色,称之为高亮
@Test
//6.高亮查询
public void toOpen() throws Exception{
//设置高亮数据
HighlightBuilder hiBuilder=new HighlightBuilder();
hiBuilder.preTags("<font style='color:red'>");//设置高亮前标签
hiBuilder.field("title");//设置高亮显示的字段
hiBuilder.postTags("</font>");//设置高亮结束标签
// 搜索数据
QueryBuilder queryBuilder= QueryBuilders.termQuery("title", "显示");
SearchResponse searchRequestBuilder = client.prepareSearch("demo1")
.setTypes("hello1")
.setQuery(queryBuilder)
.highlighter(hiBuilder)
.get();
//获取查询结果集
SearchHits searchHits = searchRequestBuilder.getHits();
System.out.println("共搜到:"+searchHits.getTotalHits()+"条结果!");
//遍历结果
for(SearchHit hit:searchHits){
System.out.println("String方式打印文档搜索内容:");
System.out.println(hit.getSourceAsString());
System.out.println("Map方式打印高亮内容");
System.out.println(hit.getHighlightFields());
System.out.println("遍历高亮集合,打印高亮片段:");
Text[] text = hit.getHighlightFields().get("title").getFragments();
for (Text str : text) {
System.out.println(str);//高亮内容的样式
}
}
//释放资源
client.close();
}
SpringDataES操作ES服务器
- 导入Spring Data ElasticSearch坐标
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>5.6.8</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>5.6.8</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.24</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--引入SpringData ES的依赖-->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>3.0.5.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.elasticsearch.plugin</groupId>
<artifactId>transport-netty4-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--测试-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.4.RELEASE</version>
</dependency>
<!--json转换工具-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>
- 创建applicationContext.xml配置文件,引入elasticsearch命名空间
配置集群连接信息、配置SpringDataES提供的模板对象、配置扫描dao所对应的包
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/data/elasticsearch
http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd
">
<!-- 扫描Dao包,自动创建实例 -->
<elasticsearch:repositories base-package="dao"/>
<!-- 配置elasticSearch的连接 -->
<!-- 配置elasticSearch的连接 -->
<elasticsearch:transport-client id="client" cluster-nodes="localhost:9301" cluster-name="my-elasticsearch"/>
<!-- ElasticSearch模版对象 -->
<bean id="elasticsearchTemplate" class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
<constructor-arg name="client" ref="client"></constructor-arg>
</bean>
</beans>
当项目为SpringBoot项目时,待补充?
3. 配置实体
基于spring data elasticsearch注解配置索引、映射和实体的关系
其中,注解解释如下:
@Document(indexName="blob3",type="article"):
indexName:索引的名称(必填项)
type:索引的类型
@Id:主键的唯一标识
@Field(index=true,analyzer="ik_smart",store=true,searchAnalyzer="ik_smart",type = FieldType.text)
index:是否设置分词
analyzer:存储时使用的分词器
searchAnalyze:搜索时使用的分词器
store:是否存储
type: 数据类型
//指定索引、文档、文档的字段信息。
//@Document 文档对象 (索引信息、文档类型 )
@Document(indexName = "demo2",type = "hello2")
public class Hello {
//@Id 文档主键 唯一标识
@Id//此处得id和_id的值默认保持一致
//@Field 每个文档的字段配置(类型、是否分词、是否存储、分词器 )
@Field(store=true, index = false,type = FieldType.Integer)
private Integer id;
@Field(index=true,analyzer="ik_smart",store=true,searchAnalyzer="ik_smart",type = FieldType.text)
private String title;
@Field(index=true,analyzer="ik_smart",store=true,searchAnalyzer="ik_smart",type = FieldType.text)
private String content;
//get\set\toString
- 编写dao接口(也称Repository仓库)
@Repository
public interface HelloRepository extends ElasticsearchRepository<Hello, Integer> {
//自定义方法,按照命名规则命名即可,SpringDataES自动实现
/**根据content或者title来查询*/
List<Hello> findByContentOrTitle(String content,String title);
/**根据content来查询*/
List<Hello> findByContent(String content);
}
- 编写测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class SpringDataESTest {
@Autowired
private HelloRepository repository;
/*@Autowired
private TransportClient client;*/
@Autowired
private ElasticsearchTemplate template;
/**
* 创建索引和映射
*/
@Test
public void createIndex() {
template.createIndex(Hello.class);
//上边创建索引中包含映射
// elasticsearchTemplate.putMapping(Hello.class);
}
/**
* 添加文档
*/
@Test
public void createDocument() {
Hello hello = new Hello();
hello.setId(6);
hello.setTitle("SpringData");
hello.setContent("data内容被我修改了");
//将文档写入索引库
repository.save(hello);
}
/**
* 根据_id删除文档
*/
@Test
public void deleteDocument() {
repository.deleteById(5);
}
/**
* 更新文档:根据id来删除旧的插入新的
*/
@Test
public void updateDocument() {
Hello hello = new Hello();
hello.setId(5);
hello.setTitle("SpringData");
hello.setContent("内容+修改了");
//将文档写入索引库
repository.save(hello);
}
/**
* 查询所有
*/
@Test
public void findAll() {
Iterable<Hello> all = repository.findAll();
// all.forEach(a-> System.out.println(a));
Iterator<Hello> iterator = all.iterator();
while (iterator.hasNext()) {
Hello next = iterator.next();
System.out.println(next);
}
}
/**
* 根据_id查询单个
*/
@Test
public void findById() {
Optional<Hello> byId = repository.findById(1);
Hello hello = byId.get();
System.out.println(hello);
}
/**
* 自定义查询方法
*/
@Test
public void findByMy() {
List<Hello> byContentOrTitle = repository.findByContentOrTitle("修改了", "数据");
//stream流遍历
byContentOrTitle.stream().forEach(System.out::println);
}
/**
* 查询之拆词词间关系为and
* 某个词不是数据中内容则会查询为空null
*/
@Test
public void findByContentAnd() {
//对内容进行拆分,拆分后关系为and,数据中没有”我“这个词,故查询失败
List<Hello> byContentOrTitle = repository.findByContent("我修改了内容");
//stream流遍历
byContentOrTitle.stream().forEach(System.out::println);
}
/**
* 此方法常用
* 查询之拆词词间关系变为or
*/
@Test
public void findByContentOr() {
//使用原生方法进行queryString进行查询
QueryBuilder queryBuilder=new QueryStringQueryBuilder("我修改了内容")
.defaultField("content");
NativeSearchQuery build = new NativeSearchQueryBuilder()
.withQuery(queryBuilder)
.withPageable(PageRequest.of(0, 2))
.build();
List<Hello> hellos = template.queryForList(build, Hello.class);
hellos.stream().forEach(System.out::println);
}
自定义查询方法命名规则
关键字 | 命名规则 | 解释 | 示例 |
---|---|---|---|
and | findByField1AndField2 | 根据Field1和Field2获得数据 | findByTitleAndContent |
or | findByField1OrField2 | 根据Field1或Field2获得数据 | findByTitleOrContent |
is | findByField | 根据Field获得数据 | findByTitle |
not | findByFieldNot | 根据Field获得补集数据 | findByTitleNot |
between | findByFieldBetween | 获得指定范围的数据 | findByPriceBetween |
lessThanEqual | findByFieldLessThan | 获得小于等于指定值的数据 | findByPriceLessThan |
拆词实现字段or查询、
注意:拆词查询后搜索词之间是and关系,一般应该为or来进行查询。
实现:使用原生的查询一个
步骤:
1.创建NativeSearchQuery对象
QueryBuilder来构造条件
2.使用ES的模板对象来执行查询
3.获取查询结果
@Test
public void findByContentOr() {
//使用原生方法进行queryString进行查询
//构造查询条件
QueryBuilder queryBuilder=new QueryStringQueryBuilder("我修改了内容")
.defaultField("content");
//生成模板需要的对象以及设置分页信息
NativeSearchQuery build = new NativeSearchQueryBuilder()
.withQuery(queryBuilder)
.withPageable(PageRequest.of(0, 2))
.build();
//使用模板执行查询
List<Hello> hellos = template.queryForList(build, Hello.class);
hellos.stream().forEach(System.out::println);
}
SpringData是一个用于简化数据库访问,并支持云服务的开源框架
配置
pojo中已经指定了索引和type名
操作
@ID
_id的生成配置地方寻找???
查询时候term和querystring怎么区别?
此处的查询是分词后每个词是and关系即都需要满足,如果想要实现or的操作需要使用原生的查询