100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > Elastic Search Java API(文档操作API Query DSL查询API) es搜索引擎实战demo

Elastic Search Java API(文档操作API Query DSL查询API) es搜索引擎实战demo

时间:2023-09-22 11:58:53

相关推荐

Elastic Search Java API(文档操作API Query DSL查询API) es搜索引擎实战demo

elastic search实战小demo:/simonsfan/springboot-quartz-demo,分支:feature_es

之前在 Elastic Search之Search API(Query DSL)、Elasticsearch之索引和文档API 文章中讲到过elastic search(以下简称es)的以下常用的原生api,本篇开始讲述如何结合java开发使用es api进行索引的CRUD及复杂查询。我这里以springboot中使用为例方便测试,首先需要引入maven依赖:

<dependency><groupId>org.elasticsearch.client</groupId><artifactId>transport</artifactId><version>5.6.1</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.7</version></dependency>

springboot配置文件application.yml中加如下配置,注意9300是es与java交互的端口,不是es与http交互的端口号9200:

elasticsearch:cluster:name: elasticsearchhost: 127.0.0.1port: 9300

建立测试用到的movie_index索引并且新增两条测试数据:

PUT /movie_index{"mappings": {"info": {"properties": {"actors": {"type": "text"},"alias": {"type": "text"},"directors": {"type": "text"},"introduction": {"type": "text"},"label": {"type": "text"},"name": {"type": "text"},"score": {"type": "float"},"release": {"type": "date"},"area": {"type": "keyword"}}}}}POST /movie_index/info{"name": "毒液","alias": "毒液","actors": "汤姆·哈迪 米歇尔·威廉姆斯 伍迪·哈里森 里兹·阿迈德 珍妮·斯蕾特","directors": "鲁本·弗雷斯彻","score": 9,"area": "美国","label": " 美国 电影 动作 好莱坞 VIP电影 VIP尊享 动作 新片","release": "","introduction": "03月17日,索尼宣布将为蜘蛛侠的死对头“毒液”(Venom)打造外传电影,并计划于10月5日上映。《毒液》被视作蜘蛛侠系列的外传,将由《超凡蜘蛛侠2》的编剧艾里克斯·库兹曼(《木乃伊》)执导,《蜘蛛侠:英雄归来》的制片人马修·托马齐以及漫威影业前CEO阿维·阿拉德担任制片,由丹特·哈珀(《明日边缘》)编剧。他们表示,此片与汤姆·赫兰德主演的蜘蛛侠三部曲没什么关系,是一个独立的外传。关于此片的更多细节并未透露。 3月28日,索尼确认《毒液》将以R级的形式进行开发。 5月,确认英国演员汤姆·哈迪将出演漫威蜘蛛侠衍生片《毒液》,将扮演自由摄影师Eddie Brock 。 6月,制片人艾米·帕斯卡尔证实影片将和漫威电影宇宙连接,作为附属电影,并且有机会让汤姆·赫兰德回归饰演蜘蛛侠。"}POST /movie_index/info{"name": "我不是药神","alias": "我不是药神","actors": "徐峥 王传君 周一围 谭卓 章宇","directors": "文牧野","score": 9.2,"area": "内地","label": "国内院线 VIP电影 剧情 VIP尊享 院线 喜剧 喜剧 新片 剧情","release": "","introduction": "普通中年男子程勇(徐峥 饰)经营着一家保健品店,失意又失婚。不速之客吕受益(王传君 饰)的到来,让他开辟了一条去印度买药做“代购”的新事业,虽然困难重重,但他在这条“买药之路”上发现了商机,一发不可收拾地做起了治疗慢粒白血病的印度仿制药独家代理商。赚钱的同时,他也认识了几个病患及家属,为救女儿被迫做舞女的思慧(谭卓 饰)、说一口流利“神父腔”英语的刘牧师(杨新鸣 饰),以及脾气暴烈的“黄毛”(章宇 饰),几个人合伙做起了生意,利润倍增的同时也危机四伏。程勇昔日的小舅子曹警官(周一围 饰)奉命调查仿制药的源头,假药贩子张长林(王砚辉 饰)和瑞士正牌医药代表(李乃文 饰)也对其虎视眈眈,生意逐渐变成了一场关于救赎的拉锯战。"}

首先注入elastic search的客户端TransportClient:

@Configurationpublic class ElasticSearchConfig {@Value("${elasticsearch.host}")private String esHost;@Value("${elasticsearch.port}")private int esPort;@Value("${elasticsearch.cluster.name}")private String esName;@Beanpublic TransportClient esClient() throws UnknownHostException {TransportClient client = null;try {Settings settings = Settings.builder().put("client.transport.sniff", true).put("cluster.name", this.esName).build();InetSocketTransportAddress master = new InetSocketTransportAddress(InetAddress.getByName(esHost), esPort);client = new PreBuiltTransportClient(settings).addTransportAddress(master);} catch (Exception e) {e.printStackTrace();}return client;}}

后续需要使用es客户端TransportClient 时直接使用@Autowired注入即可。

Document APIS

主要体现为文档的增删改查、批量操作等

Index API

index api表现为新增文档(如果索引不存在会直接新建),参数需要指定索引名称、类型、json数据三个参数,然后根据返回IndexResponse的状态判断是否新增成功:

@Autowiredprivate TransportClient transportClient;@Autowiredprivate ObjectMapper objectMapper;/*** 新增文档** @param indexTemplate* @return*/@Overridepublic String addIndex(MovieIndexTemplate indexTemplate) {if (indexTemplate == null) {return ResultUtil.fail();}try {IndexRequestBuilder indexRequestBuilder = transportClient.prepareIndex(INDEX, TYPE).setSource(objectMapper.writeValueAsBytes(indexTemplate), XContentType.JSON);IndexResponse indexResponse = indexRequestBuilder.get();if (indexResponse.status() == RestStatus.CREATED) {logger.info("name={},新增文档成功", indexTemplate.getName());return ResultUtil.success();}} catch (JsonProcessingException e) {logger.error("");}return ResultUtil.fail();}

@Autowiredprivate MovieSearchService movieSearchService;@Testpublic void testAddDocument() {MovieIndexTemplate indexTemplate = new MovieIndexTemplate();indexTemplate.setName("喜剧之王");indexTemplate.setAlias("喜剧之王");indexTemplate.setActors("周星驰,莫文蔚,张柏芝,吴孟达,林子善,田启文");indexTemplate.setDirectors("周星驰 李力持");indexTemplate.setIntroduction("《喜剧之王》是星辉海外有限公司出品的一部喜剧电影,由李力持、周星驰执导,周星驰、 莫文蔚、张柏芝等主演。该片于1999年2月13日在香港上映。影片讲述对喜剧情有独钟的尹天仇与舞女柳飘飘逐渐产生感情,之后在杜娟儿的帮助下,尹天仇终于获得机会演主角,但又陷入与柳飘飘、杜娟儿的三角恋漩涡之中");indexTemplate.setArea("内地");indexTemplate.setScore(9.4f);indexTemplate.setLabel("喜剧 爱情");indexTemplate.setRelease("1999");movieSearchService.addIndex(indexTemplate);}

Get API

get api用于获取指定的文档数据,接收索引名称、类型、id三个参数:

@Overridepublic String getIndex(String id) {GetResponse getResponse = transportClient.prepareGet(INDEX, TYPE, id).get();String result = getResponse.getSourceAsString();logger.info("get api result ={},", result);if (StringUtils.isEmpty(result)) {return ResultUtil.fail();}return ResultUtil.success(result);}

@Testpublic void getIndex(){String id = "hTCYWmgBBHn7EfncQOq6";movieSearchService.getIndex(id);}

get api只支持一个id,但是你可以使用multi get api来一次性传入多个id,并返回多个对应的结果集:

//multi getindexpublic void getIndex2(String[] keyword) {MultiGetResponse multiGetItemResponse = transportClient.prepareMultiGet().add(INDEX, TYPE, keyword[0]).add(INDEX, TYPE, keyword[1]).get();for (MultiGetItemResponse getItemResponse : multiGetItemResponse) {GetResponse response = getItemResponse.getResponse();String json = response.getSourceAsString();}}

Delete API

delete api用于删除指定的文档数据,同get api类似,也是接收索引名称、类型、id三个参数:

@Overridepublic String deleteIndex(String id) {DeleteRequestBuilder deleteRequestBuilder = transportClient.prepareDelete(INDEX, TYPE, id);DeleteResponse deleteResponse = deleteRequestBuilder.get();if (deleteResponse.status() == RestStatus.OK) {logger.info("");return ResultUtil.success();}return ResultUtil.fail();}

@Testpublic void deleteIndex(){String id = "hTCYWmgBBHn7EfncQOq6";movieSearchService.deleteIndex(id);}

Delete By Query API

这个删除操作根据筛选条件来删除指定数据,比单纯的根据id进行删除灵活一些,例如下面的根据电影name字段匹配删除:

@Overridepublic String deleteByQueryAction(String keyword) {BulkByScrollResponse bulkByScrollResponse = DeleteByQueryAction.INSTANCE.newRequestBuilder(transportClient).filter(QueryBuilders.matchQuery(MovieSearch.NAME, keyword)).source(INDEX).get();long deleted = bulkByScrollResponse.getDeleted();logger.info("根据条件keyword={}删除result={}", keyword, deleted);if (deleted < 1) {logger.info("根据条件keyword={}删除失败", keyword);return ResultUtil.fail();}logger.info("根据条件keyword={}删除成功", keyword);return ResultUtil.success();}

@Testpublic void deleteByQueryAction(){String name = "喜剧之王";movieSearchService.deleteByQueryAction(name);}

由于这个delete by query操作可能执行较长时间,因此你可以设置异步方式执行替代直接get,并设置这个delete by query操作的监听器,在监听器里面处理成功和失败的具体逻辑:

//异步执行delete by querypublic void deleteByQueryAction1(String keyword) {DeleteByQueryAction.INSTANCE.newRequestBuilder(transportClient).filter(QueryBuilders.matchQuery(MovieSearch.NAME, keyword)).source(INDEX).execute(new ActionListener<BulkByScrollResponse>() {@Overridepublic void onResponse(BulkByScrollResponse bulkByScrollResponse) {long deleted = bulkByScrollResponse.getDeleted();logger.info("根据条件keyword={}删除result={}", keyword, deleted);if (deleted < 1) {logger.info("根据条件keyword={}删除失败", keyword);}logger.info("根据条件keyword={}删除成功", keyword);}@Overridepublic void onFailure(Exception e) {// Hanlder the exception……}});}

Bulk API

bulk api支持批量操作,例如一个请求里面同时包含删除、新增功能:

//批量bulk操作@Overridepublic void buldOption(MovieIndexTemplate indexTemplate, String id) throws JsonProcessingException {BulkRequestBuilder bulkRequestBuilder = transportClient.prepareBulk();bulkRequestBuilder.add(transportClient.prepareDelete(INDEX, TYPE, id));bulkRequestBuilder.add(transportClient.prepareIndex(INDEX, TYPE).setSource(objectMapper.writeValueAsBytes(indexTemplate), XContentType.JSON));BulkResponse bulkItemResponses = bulkRequestBuilder.get();RestStatus status = bulkItemResponses.status();logger.info("bulk option result status={}", status);}

Update API和Reindex API这里不讲,用的不多,由于在elastic search中不推荐对Index进行修改,而应该直接删除再新增的方式,所以update和reindex api用的并不多。

Query DSL Java API

之前在Elastic Search之Search API(Query DSL)、字段类查询、复合查询一文中说到了es的原生Query DSL API,分为字段类查询和复合查询,字段类查询又可以分为单词类查询和全文匹配。

全文匹配:包括match、match_phrase、query_string、simple_query_string等查询语句;

//Match QueryMatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(MovieSearch.NAME, "毒液");//Muitl Match QueryMultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("", MovieSearch.NAME, MovieSearch.AREA, MovieSearch.INTRODUCTION, MovieSearch.ACTORS, MovieSearch.DIRECTORS);//Common Terms QueryCommonTermsQueryBuilder commonTermsQueryBuilder = monTermsQuery(MovieSearch.NAME, "毒液");//Query String QueryQueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryStringQuery("毒液").field(MovieSearch.NAME).defaultOperator(Operator.OR);//Simple Query String QuerySimpleQueryStringBuilder simpleQueryStringBuilder = QueryBuilders.simpleQueryStringQuery("毒液").field(MovieSearch.NAME);

单词匹配:包括term、terms、range等查询语句;

//Term QueryTermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(MovieSearch.NAME, "毒液");//Terms QueryTermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery(MovieSearch.NAME, "毒液", "我不是药神");//Range Query筛选评分在7~10分之间的数据集,includeLower(false)表示from是gt,反之;includeUpper(false)表示to是lt,反之QueryBuilders.rangeQuery(MovieSearch.SCORE).from(7).to(10).includeLower(false).includeUpper(false);

Compound Query

复合查询是es中用的最多的,常见的是Bool查询,包括must、should、filter、must_not,在Elastic Search之Search API(Query DSL)、字段类查询、复合查询一文中也有说到过其原生api。下面是综合使用Bool查询示例code:

public void boolDsl() {//Bool QueryBoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();//电影名称必须包含我不是药神经过分词后的文本,比如我、不、是、药、神boolQueryBuilder.must(QueryBuilders.matchQuery(MovieSearch.NAME, "我不是药神"));//排除导演是张三的电影信息boolQueryBuilder.mustNot(QueryBuilders.termQuery(MovieSearch.DIRECTORS, "张三"));//别名中应该包含药神经过分词后的文本,比如药、神boolQueryBuilder.should(QueryBuilders.matchQuery(MovieSearch.ALIAS, "药神"));//评分必须大于9(因为es对filter会有智能缓存,推荐使用)boolQueryBuilder.filter(QueryBuilders.rangeQuery(MovieSearch.SCORE).gt(9));//name、actors、introduction、alias、label 多字段匹配"药神",或的关系boolQueryBuilder.filter(QueryBuilders.multiMatchQuery("药神", MovieSearch.NAME, MovieSearch.ACTORS, MovieSearch.INTRODUCTION, MovieSearch.ALIAS, MovieSearch.LABEL));String[] includes = {MovieSearch.NAME, MovieSearch.ALIAS, MovieSearch.SCORE, MovieSearch.ACTORS, MovieSearch.DIRECTORS, MovieSearch.INTRODUCTION};SearchRequestBuilder searchRequestBuilder = transportClient.prepareSearch(INDEX).setTypes(TYPE).setQuery(boolQueryBuilder).addSort(MovieSearch.SCORE, SortOrder.DESC).setFrom(0).setSize(10).setFetchSource(includes, null);SearchResponse searchResponse = searchRequestBuilder.get();if (!RestStatus.OK.equals(searchResponse.status())) {return;}for (SearchHit searchHit : searchResponse.getHits()) {String name = (String) searchHit.getSource().get(MovieSearch.NAME);//TODO}}

根据这些基础api做了个基于es搜索引擎的demo项目,功能比较简单,就是可以根据用户输入的文本去es中实时搜索数据集,效果如下图:

项目github:/simonsfan/springboot-quartz-demo,分支:feature_es。要注意:由于这个项目之前是用来展示 "使用quartz实现定制化定时任务" 功能的,所以需要kafka服务,并且要安装elastic search服务。项目中有很多问题需要完善,有兴趣的小伙伴可以自己完善下。有问题欢迎留言交流!

上一篇:Elastic Search之分页展示

下一篇: Elastic Search与mysql数据同步方案

参考资料: es官网https://www.elastic.co/guide/en/elasticsearch/client/java-api/6.3/index.html

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。