首页 存档 技术 查看内容

用Elasticsearch为你的项目提供垂直搜索服务

2018-3-30 13:00 |来自: 互联网 356 0

摘要: 本文选自《开发者头条》3 月 25 日用户分享,感谢作者 Rick Zhu 分享。 欢迎分享:http://toutiao.io/contribute 大家知道用like搜索的性能是何其低下,尤其是当关键词前也要加%匹配的时候,即使建立了索引,也要 ...

本文选自《开发者头条》3 月 25 日用户分享,感谢作者 Rick Zhu 分享。

欢迎分享http://toutiao.io/contribute


大家知道用like搜索的性能是何其低下,尤其是当关键词前也要加%匹配的时候,即使建立了索引,也要进行全表扫描。当这种搜索的请求比较频繁的时候,数据库就会成为性能瓶颈。


我们熟知的Lucene是一款非常优秀的开源搜索引擎,不过它的使用比较复杂,产生的大量索引文件也不便于管理。


这时不妨试试elasticsearch,它不仅基于lucene,拥有和lucene一样强大的搜索功能,而且为索引文件提供了分布式管理平台,而且大大简化了搜索相关的API。


笔者以一个简单的电商中商品搜索应用为例。首先我们部署好elasticsearch(以下简称ES)。下载链接及安装步骤


ES有丰富的插件,其中有3个插件是我推荐安装的:

  • head

  • ik

  • JDBC river


外加一款chrome插件sense。


head是ES的web控制台。ik是中文分词插件,river用来把关系数据库中的数据导入ES,sense是ES的调试工具,可以方便地通过浏览器给ES集群发送各种请求。


ES的简单用法这里就不讲了,直接进入实战。

首先分析商品搜索的需求。一般来说商品搜索分两种,一种是在电商首页的搜索条上敲商品名支持自动补全和联想功能,一种是根据商品名加上其它参数,比如价格区间做模糊匹配。


针对这两种不同的需求,我们需要为商品在ES中建立两个type,类比关系数据库,相当于建两张表,用于自动补全的type称之为keyword_goods,因为主要用于关键字搜索,只要保存关键字和商品ID就可以了,而用于模糊匹配查找的type称为goods,里面要保存商品的各种属性信息,以便支持filter查找。


首先我们创建index和type,在创建时添加mapping和setting如下:

mapping:

{
  "goods": {
    "properties": {
      "name": {
        "type": "string",
        "index": "analyzed",
        "analyzer": "cn_analyzer"
      },
      "sn": {
        "type": "string",
        "index": "not_analyzed"
      },
      "shop_price": {
        "type": "float",
        "index": "not_analyzed"
      },
      "shop_id": {
        "type": "long",
        "index": "not_analyzed"
      },
      "cate_id": {
        "type": "long",
        "index": "not_analyzed"
      }
    }
  }
}

setting:

{
    "index": {
            "analysis": {
                "analyzer": {
                    "cn_analyzer": {
                        "type" : "custom",
                        "tokenizer" : "ik"
                    }
                }
            }
     }
 }

在setting里申明使用ik分词器作为cnanalyzer,默认情况下ES使用雪球(snowball)分词器,不支持中文词汇。在mapping中申明对name字段进行cnanalyzer中文分词(其实商品名很短,不需要分词,长文本搜索才用的到,这里只为演示)。mapping中列出商品需要被索引的字段。


在服务器启动的时候检查type是否存在,如果不存在创建type

public void createIndice(String mapping, String settings,  
            String indice, String type) throws Exception {
        Client client = searchClient.getClient();
        CreateIndexRequest indexRequest = new CreateIndexRequest(indice);
        if (mapping != null) {
            indexRequest.mapping(type, mapping);
        }
        if (settings != null) {
            indexRequest.settings(settings);
        }
        client.admin().indices().create(indexRequest).actionGet();
    }
@PostConstruct
    public void initService() {
        log.debug("Initializing search service");
        try {
            index.init(searchClient);
            keyword.init(searchClient);
        } catch (Exception e) {
            log.error("Cannot initialize SearchService correctly, will be initialized lazily", e);
        }
    }

说明两点:

  1. 建立type的时候可以不显式地导入mapping和setting,ES会把传入的参数全部建立索引。这里选择导入是为了更精确地控制ES对每个字段的索引操作。

  2. 使用@PostConstruct这个spring中的注解,使得服务器启动之后,spring配置加载完后自动去检查并创建goods和keyword_goods两个type


这样就类似于JPA的方式,而type就类似于数据库的表而mapping就相当于建表的sql。


当用户插入新的商品时,就要在两个type中建立索引,spring的配置如下:

声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部