文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

如何使用elasticsearch搭建自己的搜索系统

2024-04-02 19:55

关注

这期内容当中小编将会给大家带来有关如何使用elasticsearch搭建自己的搜索系统,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

什么是elasticsearch#

Elasticsearch 是一个开源的高度可扩展的全文搜索和分析引擎,拥有查询近实时的超强性能。

大名鼎鼎的Lucene 搜索引擎被广泛用于搜索领域,但是操作复杂繁琐,总是让开发者敬而远之。而 Elasticsearch将 Lucene 作为其核心来实现所有索引和搜索的功能,通过简单的 RESTful 语法来隐藏掉 Lucene 的复杂性,从而让全文搜索变得简单

ES在Lucene基础上,提供了一些分布式的实现:集群,分片,复制等。

搜索为什么不用MySQL而用es#

我们本文案例是一个迷你商品搜索系统,为什么不考虑使用MySQL来实现搜索功能呢?原因如下:

es在大厂中的应用情况#

es客户端选型#

spring-boot-starter-data-elasticsearch#

我相信你看到的网上各类公开课视频或者小项目均推荐使用这款springboot整合过的es客户端,但是我们要say no!

如何使用elasticsearch搭建自己的搜索系统

此图是引入的最新版本的依赖,我们可以看到它所使用的es-high-client也为6.8.7,而es7.x版本都已经更新很久了,这里许多新特性都无法使用,所以版本滞后是他最大的问题。而且它的底层也是highclient,我们操作highclient可以更灵活。我呆过的两个公司均未采用此客户端。

elasticsearch-rest-high-level-client#

这是官方推荐的客户端,支持最新的es,其实使用起来也很便利,因为是官方推荐所以在特性的操作上肯定优于前者。而且该客户端与TransportClient不同,不存在并发瓶颈的问题,官方首推,必为精品!

搭建自己的迷你搜索系统#

引入es相关依赖,除此之外需引入springboot-web依赖、jackson依赖以及lombok依赖等。

Copy	<properties>
        <es.version>7.3.2</es.version>
    </properties>
		<!-- high client-->
	<dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>${es.version}</version>
        <exclusions>
            <exclusion>
                <groupId>org.elasticsearch.client</groupId>
                <artifactId>elasticsearch-rest-client</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.elasticsearch</groupId>
                <artifactId>elasticsearch</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.elasticsearch</groupId>
        <artifactId>elasticsearch</artifactId>
        <version>${es.version}</version>
    </dependency>
    <!--rest low client high client以来低版本client所以需要引入-->
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-client</artifactId>
        <version>${es.version}</version>
    </dependency>

es配置文件es-config.properties

Copyes.host=localhost
es.port=9200
es.token=es-token
es.charset=UTF-8
es.scheme=http
es.client.connectTimeOut=5000
es.client.socketTimeout=15000

封装RestHighLevelClient

Copy@Configuration@PropertySource("classpath:es-config.properties")public class RestHighLevelClientConfig {    @Value("${es.host}")    private String host;    @Value("${es.port}")    private int port;    @Value("${es.scheme}")    private String scheme;    @Value("${es.token}")    private String token;    @Value("${es.charset}")    private String charSet;    @Value("${es.client.connectTimeOut}")    private int connectTimeOut;    @Value("${es.client.socketTimeout}")    private int socketTimeout;    @Bean
    public RestClientBuilder restClientBuilder() {
        RestClientBuilder restClientBuilder = RestClient.builder(                new HttpHost(host, port, scheme)
        );
        Header[] defaultHeaders = new Header[]{                new BasicHeader("Accept", "*
    public CreateIndexResponse createIndex(String indexName, String settings, String mapping) throws IOException {
        CreateIndexRequest request = new CreateIndexRequest(indexName);        if (null != settings && !"".equals(settings)) {
            request.settings(settings, XContentType.JSON);
        }        if (null != mapping && !"".equals(mapping)) {
            request.mapping(mapping, XContentType.JSON);
        }        return client.indices().create(request, RequestOptions.DEFAULT);
    }    
    public boolean indexExists(String indexName) throws IOException {
        GetIndexRequest request = new GetIndexRequest(indexName);        return client.indices().exists(request, RequestOptions.DEFAULT);
    }    
    
    public SearchResponse search(String field, String key, String rangeField, String 
                                 from, String to,String termField, String termVal, 
                                 String ... indexNames) throws IOException{
        SearchRequest request = new SearchRequest(indexNames);
        SearchSourceBuilder builder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(new MatchQueryBuilder(field, key)).must(new RangeQueryBuilder(rangeField).from(from).to(to)).must(new TermQueryBuilder(termField, termVal));
        builder.query(boolQueryBuilder);
        request.source(builder);
        log.info("[搜索语句为:{}]",request.source().toString());        return client.search(request, RequestOptions.DEFAULT);
    }    
    public BulkResponse importAll(String indexName, boolean isAutoId, String  source) throws IOException{        if (0 == source.length()){            //todo 抛出异常 导入数据为空
        }
        BulkRequest request = new BulkRequest();
        JsonNode jsonNode = mapper.readTree(source);        if (jsonNode.isArray()) {            for (JsonNode node : jsonNode) {                if (isAutoId) {
                    request.add(new IndexRequest(indexName).source(node.asText(), XContentType.JSON));
                } else {
                    request.add(new IndexRequest(indexName)
                            .id(node.get("id").asText())
                            .source(node.asText(), XContentType.JSON));
                }
            }
        }        return client.bulk(request, RequestOptions.DEFAULT);
    }

创建索引,这里的settings是设置索引是否设置复制节点、设置分片个数,mappings就和数据库中的表结构一样,用来指定各个字段的类型,同时也可以设置字段是否分词(我们这里使用ik中文分词器)、采用什么分词方式。

Copy   @Test
    public void createIdx() throws IOException {
        String settings = "" +                "  {\n" +                "      \"number_of_shards\" : \"2\",\n" +                "      \"number_of_replicas\" : \"0\"\n" +                "   }";
        String mappings = "" +                "{\n" +                "    \"properties\": {\n" +                "      \"itemId\" : {\n" +                "        \"type\": \"keyword\",\n" +                "        \"ignore_above\": 64\n" +                "      },\n" +                "      \"urlId\" : {\n" +                "        \"type\": \"keyword\",\n" +                "        \"ignore_above\": 64\n" +                "      },\n" +                "      \"sellAddress\" : {\n" +                "        \"type\": \"text\",\n" +                "        \"analyzer\": \"ik_max_word\", \n" +                "        \"search_analyzer\": \"ik_smart\",\n" +                "        \"fields\": {\n" +                "          \"keyword\" : {\"ignore_above\" : 256, \"type\" : \"keyword\"}\n" +                "        }\n" +                "      },\n" +                "      \"courierFee\" : {\n" +                "        \"type\": \"text\n" +                "      },\n" +                "      \"promotions\" : {\n" +                "        \"type\": \"text\",\n" +                "        \"analyzer\": \"ik_max_word\", \n" +                "        \"search_analyzer\": \"ik_smart\",\n" +                "        \"fields\": {\n" +                "          \"keyword\" : {\"ignore_above\" : 256, \"type\" : \"keyword\"}\n" +                "        }\n" +                "      },\n" +                "      \"originalPrice\" : {\n" +                "        \"type\": \"keyword\",\n" +                "        \"ignore_above\": 64\n" +                "      },\n" +                "      \"startTime\" : {\n" +                "        \"type\": \"date\",\n" +                "        \"format\": \"yyyy-MM-dd HH:mm:ss\"\n" +                "      },\n" +                "      \"endTime\" : {\n" +                "        \"type\": \"date\",\n" +                "        \"format\": \"yyyy-MM-dd HH:mm:ss\"\n" +                "      },\n" +                "      \"title\" : {\n" +                "        \"type\": \"text\",\n" +                "        \"analyzer\": \"ik_max_word\", \n" +                "        \"search_analyzer\": \"ik_smart\",\n" +                "        \"fields\": {\n" +                "          \"keyword\" : {\"ignore_above\" : 256, \"type\" : \"keyword\"}\n" +                "        }\n" +                "      },\n" +                "      \"serviceGuarantee\" : {\n" +                "        \"type\": \"text\",\n" +                "        \"analyzer\": \"ik_max_word\", \n" +                "        \"search_analyzer\": \"ik_smart\",\n" +                "        \"fields\": {\n" +                "          \"keyword\" : {\"ignore_above\" : 256, \"type\" : \"keyword\"}\n" +                "        }\n" +                "      },\n" +                "      \"venue\" : {\n" +                "        \"type\": \"text\",\n" +                "        \"analyzer\": \"ik_max_word\", \n" +                "        \"search_analyzer\": \"ik_smart\",\n" +                "        \"fields\": {\n" +                "          \"keyword\" : {\"ignore_above\" : 256, \"type\" : \"keyword\"}\n" +                "        }\n" +                "      },\n" +                "      \"currentPrice\" : {\n" +                "        \"type\": \"keyword\",\n" +                "        \"ignore_above\": 64\n" +                "      }\n" +                "   }\n" +                "}";
        clientService.createIndex("idx_item", settings, mappings);
    }

分词技巧

我们向es导入十万条淘宝双11活动数据作为我们的样本数据,数据结构如下所示

Copy{	"_id": "https://detail.tmall.com/item.htm?id=538528948719\u0026skuId=3216546934499",	"卖家地址": "上海",	"快递费": "运费: 0.00元",	"优惠活动": "满199减10,满299减30,满499减60,可跨店",	"商品ID": "538528948719",	"原价": "2290.00",	"活动开始时间": "2016-11-11 00:00:00",	"活动结束时间": "2016-11-11 23:59:59",	"": "【天猫海外直营】 ReFa CARAT RAY 黎珐 双球滚轮波光美容仪",	"服务保障": "正品保证;赠运费险;极速退款;七天退换",	"会场": "进口尖货",	"现价": "1950.00"}

调用上面封装的批量导入方法进行导入

Copy    @Test
    public void importAll() throws IOException {
        clientService.importAll("idx_item", true, itemService.getItemsJson());
    }

我们调用封装的搜索方法进行搜索,搜索产地为武汉、价格在11-149之间的相关酒产品,这与我们淘宝中设置筛选条件搜索商品操作一致。

Copy    @Test
    public void search() throws IOException {
        SearchResponse search = clientService.search("title", "酒", "currentPrice",                "11", "149", "sellAddress", "武汉");
        SearchHits hits = search.getHits();
        SearchHit[] hits1 = hits.getHits();        for (SearchHit documentFields : hits1) {
            System.out.println( documentFields.getSourceAsString());
        }
    }

我们得到以下搜索结果,其中_score为某一项的得分,商品就是按照它来排序。

Copy    {      "_index": "idx_item",      "_type": "_doc",      "_id": "Rw3G7HEBDGgXwwHKFPCb",      "_score": 10.995819,      "_source": {        "itemId": "525033055044",        "urlId": "https://detail.tmall.com/item.htm?id=525033055044&skuId=def",        "sellAddress": "湖北武汉",        "courierFee": "快递: 0.00",        "promotions": "满199减10,满299减30,满499减60,可跨店",        "originalPrice": "3768.00",        "startTime": "2016-11-01 00:00:00",        "endTime": "2016-11-11 23:59:59",        "title": "酒嗨酒 西班牙原瓶原装进口红酒蒙德干红葡萄酒6只装整箱送酒具",        "serviceGuarantee": "破损包退;正品保证;公益宝贝;不支持7天退换;极速退款",        "venue": "食品主会场",        "currentPrice": "151.00"
      }
    }

扩展性思考#

上述就是小编为大家分享的如何使用elasticsearch搭建自己的搜索系统了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注亿速云行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯