新建项目

新建一个springboot项目springboot_es用于本次与elasticsearch的整合,如下图

引入依赖

修改我们的pom.xml,加入spring-boot-starter-data-elasticsearch

<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-data-elasticsearch</artifactid>
</dependency>

编写配置文件

由于elasticsearch从7.x版本开始淡化transportclient甚至于在8.x版本中遗弃,所以spring data elasticsearch推荐我们使用rest客户端resthinglevelclient(端口号使用9200)以及接口elasticsearchrespositoy

  • resthighlevelclient 更强大,更灵活,但是不能友好的操作对象
  • elasticsearchrepository 对象操作友好

首先我们编写配置文件如下

/**
 * elasticsearch rest client config
 * @author christy
 * @date 2021/4/29 19:40
 **/
@configuration
public class elasticsearchrestclientconfig extends abstractelasticsearchconfiguration{
    
  	@override
    @bean
    public resthighlevelclient elasticsearchclient() {
        final clientconfiguration clientconfiguration = clientconfiguration.builder()
                .connectedto("192.168.8.101:9200")
                .build();
        return restclients.create(clientconfiguration).rest();
    }

}

springboot操作es

 resthighlevelclient方式

有了上面的rest client,我们就可以在其他的地方注入该客户端对elasticsearch进行操作。我们新建一个测试文件,使用客户端对elasticsearch进行基本的操作

1.注入restclient

/**
 * elasticsearch rest client操作
 *
 * resthighlevelclient 更强大,更灵活,但是不能友好的操作对象
 * elasticsearchrepository 对象操作友好
 *
 * 我们使用rest client 主要测试文档的操作
 * @author christy
 * @date 2021/4/29 19:51
 **/
@springboottest
public class testrestclient {
    // 复杂查询使用:比如高亮查询
    @autowired
    private resthighlevelclient resthighlevelclient;
}

2.插入一条文档

/**
 * 新增一条文档
 * @author christy
 * @date 2021/4/29 20:17
 */
@test
public void testadd() throws ioexception {
    /**
      * 向es中的索引christy下的type类型中添加一天文档
      */
    indexrequest indexrequest = new indexrequest("christy","user","11");
    indexrequest.source("{\"name\":\"齐天大圣孙悟空\",\"age\":685,\"bir\":\"1685-01-01\",\"introduce\":\"花果山水帘洞美猴王齐天大圣孙悟空是也!\"," +
                        "\"address\":\"花果山\"}", xcontenttype.json);
    indexresponse indexresponse = resthighlevelclient.index(indexrequest, requestoptions.default);
    system.out.println(indexresponse.status());
}

我们可以看到文档插入成功,我们去kibana中查询该条文档

完全没有问题的。

3.删除一条文档

/**
 * 删除一条文档
 * @author christy
 * @date 2021/4/29 20:18
 */
@test
public void deletedoc() throws ioexception {
    // 我们把特朗普删除了
    deleterequest deleterequest = new deleterequest("christy","user","rybng3kbrz-sn-2f3viu");
    deleteresponse deleteresponse = resthighlevelclient.delete(deleterequest, requestoptions.default);
    system.out.println(deleteresponse.status());
  }
}

4.更新一条文档

/**
 * 更新一条文档
 * @author christy
 * @date 2021/4/29 20:19
 */
@test
public void updatedoc() throws ioexception {
    updaterequest updaterequest = new updaterequest("christy","user","p4atg3kbrz-sn-2fmfjj");
    updaterequest.doc("{\"name\":\"调皮捣蛋的hardy\"}",xcontenttype.json);
    updateresponse updateresponse = resthighlevelclient.update(updaterequest, requestoptions.default);
    system.out.println(updateresponse.status());
}

5.批量更新文档

/**
 * 批量更新
 * @author christy
 * @date 2021/4/29 20:42
 */
@test
public void bulkupdate() throws ioexception {
    bulkrequest bulkrequest = new bulkrequest();
    // 添加
    indexrequest indexrequest = new indexrequest("christy","user","13");
    indexrequest.source("{\"name\":\"天蓬元帅猪八戒\",\"age\":985,\"bir\":\"1685-01-01\",\"introduce\":\"天蓬元帅猪八戒因调戏嫦娥被贬下凡\",\"address\":\"高老庄\"}", xcontenttype.json);
    bulkrequest.add(indexrequest);

    // 删除
    deleterequest deleterequest01 = new deleterequest("christy","user","pyatg3kbrz-sn-2fmfjj");
    deleterequest deleterequest02 = new deleterequest("christy","user","uhtyghkbexavqsl4f9lj");
    deleterequest deleterequest03 = new deleterequest("christy","user","c8zcghkb5kgtrutelye_");
    bulkrequest.add(deleterequest01);
    bulkrequest.add(deleterequest02);
    bulkrequest.add(deleterequest03);

    // 修改
    updaterequest updaterequest = new updaterequest("christy","user","10");
    updaterequest.doc("{\"name\":\"炼石补天的女娲\"}",xcontenttype.json);
    bulkrequest.add(updaterequest);

    bulkresponse bulkresponse = resthighlevelclient.bulk(bulkrequest, requestoptions.default);
    bulkitemresponse[] items = bulkresponse.getitems();
    for (bulkitemresponse item : items) {
      system.out.println(item.status());
    }
}

在kibana中查询结果

6.查询文档

@test
public void testsearch() throws ioexception {
    //创建搜索对象
    searchrequest searchrequest = new searchrequest("christy");
    //搜索构建对象
    searchsourcebuilder searchsourcebuilder = new searchsourcebuilder();

    searchsourcebuilder.query(querybuilders.matchallquery())//执行查询条件
      .from(0)//起始条数
      .size(10)//每页展示记录
      .postfilter(querybuilders.matchallquery()) //过滤条件
      .sort("age", sortorder.desc);//排序

    //创建搜索请求
    searchrequest.types("user").source(searchsourcebuilder);

    searchresponse searchresponse = resthighlevelclient.search(searchrequest, requestoptions.default);

    system.out.println("符合条件的文档总数: "+searchresponse.gethits().gettotalhits());
    system.out.println("符合条件的文档最大得分: "+searchresponse.gethits().getmaxscore());
    searchhit[] hits = searchresponse.gethits().gethits();
    for (searchhit hit : hits) {
      system.out.println(hit.getsourceasmap());
    }
}

elasticsearchrepository方式

1.准备工作

elasticsearchrepository方式主要通过注解和对接口实现的方式来实现es的操作,我们在实体类上通过注解配置es索引的映射关系后,当实现了elasticsearchrepository接口的类第一次操作es进行插入文档的时候,es会自动生成所需要的一切。但是该种方式无法实现高亮查询,想要实现高亮查询只能使用resthighlevelclient

开始之前我们需要熟悉一下接口方式为我们提供的注解,以及编写一些基础的类

1.清空es数据

2.了解注解

@document: 代表一个文档记录

indexname: 用来指定索引名称

type: 用来指定索引类型

@id: 用来将对象中id和es中_id映射

@field: 用来指定es中的字段对应mapping

type: 用来指定es中存储类型

analyzer: 用来指定使用哪种分词器

3.新建实体类

/**
 * 用在类上作用:将emp的对象映射成es中一条json格式文档
 * indexname: 用来指定这个对象的转为json文档存入那个索引中 要求:es服务器中之前不能存在此索引名
 * type     : 用来指定在当前这个索引下创建的类型名称
 *
 * @author christy
 * @date 2021/4/29 21:22
 */
@data
@document(indexname = "christy",type = "user")
public class user {
    @id //用来将对象中id属性与文档中_id 一一对应
    private string id;

    // 用在属性上 代表mapping中一个属性 一个字段 type:属性 用来指定字段类型 analyzer:指定分词器
    @field(type = fieldtype.text,analyzer = "ik_max_word")
    private string name;

    @field(type = fieldtype.integer)
    private integer age;

    @field(type = fieldtype.date)
    @jsonformat(pattern = "yyyy-mm-dd")
    private date bir;

    @field(type = fieldtype.text,analyzer = "ik_max_word")
    private string content;

    @field(type = fieldtype.text,analyzer = "ik_max_word")
    private string address;
}

4.userrepository

/**
 * @author christy
 * @date 2021/4/29 21:23
 **/
public interface 
  extends elasticsearchrepository<user,string> {
}

5.testuserrepository

/**
 * @author christy
 * @date 2021/4/29 21:51
 **/
@springboottest
public class testuserrepository {
    @autowired
    private userrepository userrepository;

}

2.保存文档

@test
public void testsaveandupdate(){
  user user = new user();
  // id初识为空,此操作为新增
  user.setid(uuid.randomuuid().tostring());
  user.setname("唐三藏");
  user.setbir(new date());
  user.setintroduce("西方世界如来佛祖大弟子金蝉子转世,十世修行的好人,得道高僧!");
  user.setaddress("大唐白马寺");
  userrepository.save(user);
}

3.修改文档

@test
public void testsaveandupdate(){
    user user = new user();
  	// 根据id修改信息
    user.setid("1666eb47-0bbf-468b-ab45-07758c741461");
    user.setname("唐三藏");
    user.setbir(new date());
    user.setintroduce("俗家姓陈,状元之后。西方世界如来佛祖大弟子金蝉子转世,十世修行的好人,得道高僧!");
    user.setaddress("大唐白马寺");
    userrepository.save(user);
}

4.删除文档

repository接口默认提供了4种删除方式,我们演示根据id进行删除

@test
public void deletedoc(){
  	userrepository.deletebyid("1666eb47-0bbf-468b-ab45-07758c741461");
}

5.检索一条记录

@test
public void testfindone(){
    optional<user> optional = userrepository.findbyid("1666eb47-0bbf-468b-ab45-07758c741461");
    system.out.println(optional.get());
}

6.查询所有

@test
public void testfindall(){
    iterable<user> all = userrepository.findall();
    all.foreach(user-> system.out.println(user));
}

7.排序

@test
public void testfindallsort(){
    iterable<user> all = userrepository.findall(sort.by(sort.order.asc("age")));
    all.foreach(user-> system.out.println(user));
}

8.分页

@test
public void testfindpage(){
    //pagerequest.of 参数1: 当前页-1
    page<user> search = userrepository.search(querybuilders.matchallquery(), pagerequest.of(1, 1));
    search.foreach(user-> system.out.println(user));
}

9.自定义查询

先给大家看一个表,是不是很晕_(¦3」∠)_

keyword sample elasticsearch query string
and findbynameandprice {"bool" : {"must" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}
or findbynameorprice {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}
is findbyname {"bool" : {"must" : {"field" : {"name" : "?"}}}}
not findbynamenot {"bool" : {"must_not" : {"field" : {"name" : "?"}}}}
between findbypricebetween {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
lessthanequal findbypricelessthan {"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
greaterthanequal findbypricegreaterthan {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}
before findbypricebefore {"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
after findbypriceafter {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}
like findbynamelike {"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}
startingwith findbynamestartingwith {"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}
endingwith findbynameendingwith {"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}}
contains/containing findbynamecontaining {"bool" : {"must" : {"field" : {"name" : {"query" : "**?**","analyze_wildcard" : true}}}}}
in findbynamein
(collection<string>names)
{"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}}
notin findbynamenotin
(collection<string>names)
{"bool" : {"must_not" : {"bool" : {"should" : {"field" : {"name" : "?"}}}}}}
near findbystorenear not supported yet !
true findbyavailabletrue {"bool" : {"must" : {"field" : {"available" : true}}}}
false findbyavailablefalse {"bool" : {"must" : {"field" : {"available" : false}}}}
orderby findbyavailable
trueorderbynamedesc
{"sort" : [{ "name" : {"order" : "desc"} }],"bool" : {"must" : {"field" : {"available" : true}}}}

这个表格看起来复杂,实际上也不简单,但是确实很牛逼。我们只要按照上面的定义在接口中定义相应的方法,无须写实现就可实现我们想要的功能

举个例子,上面有个findbyname是下面这样定义的

假如我们现在有个需求需要按照名字查询用户,我们可以在userrepository中定义一个方法,如下

// 根据姓名查询
list<user> findbyname(string name);

系统提供的查询方法中findby是一个固定写法,像上面我们定义的方法findbyname,其中name是我们实体类中的属性名,这个必须对应上。也就是说这个findbyname不仅仅局限于name,还可以findbyaddress、findbyage等等;

现在就拿findbyname来讲,我们要查询名字叫唐三藏的用户

@test
public void testfindbyname(){
    list<user> userlist = userrepository.findbyname("唐三藏");
    userlist.foreach(user-> system.out.println(user));
}

其实就是框架底层直接使用下面的命令帮我们实现的查询

get /christy/user/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "name":"?"
          }
        }
      ]
    }
  }
}

10.高亮查询

我们上面说了,elasticsearchrepository实现不了高亮查询,想要实现高亮查询还是需要使用resthighlevelclient方式。最后我们使用rest clientl实现一次高亮查询

@test
public void testhighlightquery() throws ioexception, parseexception {
    // 创建搜索请求
    searchrequest searchrequest = new searchrequest("christy");
    // 创建搜索对象
    searchsourcebuilder searchsourcebuilder = new searchsourcebuilder();
    searchsourcebuilder.query(querybuilders.termquery("introduce", "唐僧"))    // 设置查询条件
      .from(0)    // 起始条数(当前页-1)*size的值
      .size(10)   // 每页展示条数
      .sort("age", sortorder.desc)    // 排序
      .highlighter(new highlightbuilder().field("*").requirefieldmatch(false).pretags("<span style='color:red;'>").posttags("</span>"));  // 设置高亮
    searchrequest.types("user").source(searchsourcebuilder);

    searchresponse searchresponse = resthighlevelclient.search(searchrequest, requestoptions.default);

    searchhit[] hits = searchresponse.gethits().gethits();
    list<user> userlist = new arraylist<>();
    for (searchhit hit : hits) {
      map<string, object> sourceasmap = hit.getsourceasmap();

      user user = new user();
      user.setid(hit.getid());
      user.setage(integer.parseint(sourceasmap.get("age").tostring()));
      user.setbir(new simpledateformat("yyyy-mm-dd").parse(sourceasmap.get("bir").tostring()));
      user.setintroduce(sourceasmap.get("introduce").tostring());
      user.setname(sourceasmap.get("name").tostring());
      user.setaddress(sourceasmap.get("address").tostring());

      map<string, highlightfield> highlightfields = hit.gethighlightfields();
      if(highlightfields.containskey("name")){
        user.setname(highlightfields.get("name").fragments()[0].tostring());
      }

      if(highlightfields.containskey("introduce")){
        user.setintroduce(highlightfields.get("introduce").fragments()[0].tostring());
      }

      if(highlightfields.containskey("address")){
        user.setaddress(highlightfields.get("address").fragments()[0].tostring());
      }

      userlist.add(user);
    }

    userlist.foreach(user -> system.out.println(user));
}

到此这篇关于elasticsearch在springboot中使用的详细教程的文章就介绍到这了,更多相关springboot使用elasticsearch内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!