Elasticsearch 全文搜索引擎的个人学习笔记 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
CoolSpring
V2EX    Elasticsearch

Elasticsearch 全文搜索引擎的个人学习笔记

  •  2
     
  •   CoolSpring 2020-03-14 19:48:39 +08:00 5102 次点击
    这是一个创建于 2036 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这篇文章是我对自己在自学探索 Elasticsearch 全文搜索功能时学到的概念的一个总结(如果是大佬,请手下留情),大概算是 A Quick Glimpse Into Elasticsearch (Full-Text Search Part),并不一定能帮助读者建构起对于 Elasticsearch 本身客观成体系的认识。(实际上如果只是为了使用 Elasticsearch,也并不需要完全了解其工作机制。)如有需要可参考文末的官方文档和参考资料。

    为什么用 Elasticsearch 来做全文检索,而不是 MySQL 等数据库自带的检索功能?

    • 速度更快在 full-text search 领域性能更佳,数据量越大时会越明显。

    • 效果更好搜索条件可以非常灵活,分布式设计易于扩展。

    (当然 Elasticsearch 还有分析、聚合等其他功能,而 MySQL 等关系型数据库也有其更广泛丰富的需求,两者的定位并不相同。一般推荐将常规数据库作为业务数据的主要存储处,向 Elasticsearch 导入其中的部分数据进行索引以方便搜索。)

    怎么安装?

    https://www.elastic.co/cn/downloads/elasticsearch 有详细的逐步介绍。

    没有什么特殊的依赖、配置等,只需要下载解压运行,或者 yum / apt / homebrew,抑或 docker。

    安装完成后,Elasticsearch Server 默认运行于本机 9200 端口,提供 REST API这意味着现在可以通过普通的浏览器来尝试访问。http://localhost:9200/ (另有 9300 端口供 TCP 协议客户端使用和节点间通信)

    可以通过 bulk 来批量导入 JSON 形式的数据,或者使用 Logstash 等从已有数据库中导入。

    基础概念简介

    • Document 文档:序列化为 JSON 格式存储、可被索引的一个数据单元,被指定了唯一 ID。一篇文档可包含多个字段。

    • Field 字段:键-值对,字段可被定义为某一类型,如 text (适用于全文搜索),keyword (适用于仅会用于精确搜索的用途,如"status": "published"),integer,date,boolean,nested 等。

    • Index 索引:所谓的“全文搜索”不是真的在每次搜索时读取一遍全部文本,而是先建立索引,需要搜索时再查询索引。这里指的是 inverted index,而 Elasticsearch index 作为名词是另一个概念,见下文。

    • Mapping 映射:文档结构,类似于 MySQL 的 Schema,在创建 index 时指定(之后可修改),定义了文档包含字段的名称及类型。Elasticsearch 也可以在不定义 mapping 的情况下使用( schema-less ),此时它会通过第一个存入的数据推断字段类型。GET /<index>/_mapping 可以查看当前<index>的 mapping。</index></index>

    • Analyzer 分词器:索引时首先要分词才能建立索引。搜索时也是如此,若搜索的不止一个词,而是包含多个词的短语或句子,则先用分词器分离,再进行搜索。英文的分词显然较为容易,中文分词推荐 ik_max_word (最细粒度拆分出尽可能多的词语组合,官方说“适合 Term Query”)和 ik_smart (最粗粒度的拆分,“适合 Phrase 查询”)。搜索和索引的分词器可以不同,若在搜索时未指定分词器,则默认为索引的默认分词器。

    • Cluster 集群,Node 节点,Index (Indices) 索引, Shard 切片, Replica 副本切片:Elasticsearch 是分布式设计,一个对外提供服务的 Elasticsearch Server 即是一个 Cluster 集群,可以添加 Node 节点以提升性能、容量与冗余,存入的数据与收到的查询请求将被自动分配。(在同一台机器上运行多个 Node 也是可行的。)一个 Elasticsearch index 是文档的集合,这些文档一般具有相似特征。在增删改查这批文档时需要指定 index 的名字。Indices 是 index 的复数形式。一个 Elasticsearch Index 包含一个或多个 Shard 切片,一个切片实际上是一个 Lucene Index 实例( Apache Lucene 是 Elasticsearch 的底层基础),可以说 Shard 是数据的容器,但与使用 ES 服务的应用程序直接交互的是 Index。Shard 分为 primary shard 主切片和 replica shard 副本切片,文档存储于主切片中,而副本切片是主切片的一份拷贝,提供冗余并处理请求。

    • Near Real-Time 准实时:在数据存入后,它就在 1 秒内被索引而可查询。

    • Query DSL 查询专用语言:一套描述搜索条件的语言,格式为 JSON。

    • Score:搜索结果中的某篇文档与搜索要求的契合程度。一般情况下是相关度,目前 Elasticsearch 默认采用 BM25 算法,过去曾使用过 TF/IDF (词频 /逆向文档频率)。也可以在搜索请求中指定,当满足某条件时增加或减少评分,或直接给出固定分值。

    Query DSL 中和全文搜索相关的一些查询关键词

    建议使用 curl 命令来测试下面的查询。官方给出的示例:

    curl -XGET 'http://localhost:9200/twitter/_search?pretty=true' -H 'Content-Type: application/json' -d ' { "query" : { "match" : { "user": "kimchy" } } }' 

    如果要用浏览器 URI 进行简单搜索则需要用到 Lucene 查询语法(参考: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.htmlhttps://lucene.apache.org/core/2_9_4/queryparsersyntax.html ),给个例子(注意 AND ): http://localhost:9200/post_index/_search?q=user:CoolSpring%20AND%20content:Surface&size=30&pretty。

    • match: 最常用的查询方式。若输入的是短语或句子,则 Elasticsearch 会先用分词器分开,再进行搜索。只关心这些词是否都出现,而不考虑它们之间的距离。

      { "query": { "match": { "content": "quick fox" } } } 
    • match_phrase: 短语匹配。将查询内容分词成为词的列表后,搜索时考虑它们在文本中的相对位置。可以指定一个 slop 值,即允许的最大距离。slop 默认为 0,此时可以看作“完全匹配”(均出现,且相邻)。

      { "query": { "match_phrase": { "content": "包含一字不差的内容才显示为结果" } } } 
    • term: 精确匹配。比较适合用在 keyword 类型的字段,或者 board_id, topic_id, user_id 这种精确值字段( exact value string field )。

      { "query": { "term": { "user": { "value": "Kimchy", "boost": 1.0 } } } } 
    • bool: 用以连接多个布尔查询( must, must_not, should, filter )

      • must: 如其名,必须出现。

      • must_not: 不能出现。

      • should: “应该”出现。

      • filter: 必须出现。与 must 不同的是查询的评分将被忽略。

    包含多个词的 match 查询经过分词后可以改写,前述第一个 match 查询示例在内部等效于

    { "query": { "bool": { "should": [ {"term": { "text": "quick" }}, {"term": { "text": "fox" }} ] } } } 
    • minimum_should_match: 至少有几个 /百分之几的 should 语句匹配才可出现在结果中。

    • _source: 在索引时传递的原始 JSON 文档数据。索引与原内容并不相同,_source 本身不被索引、不可搜索,只是保存。

    • from, size: 易于理解,用于分页搜索中。

    • rescore: 对于 query 返回的前 n 个搜索结果(如 100-500 个)按照已有分数和新的条件进行重新评分排列。“match 返回的搜索结果不考虑词的距离所以效果不好”的问题可能很常见,一种方法时可以用简单的 bool{must: match, should: match_phrase}“使用邻近度提高相关度”的方式来解决:

      { "query": { "bool": { "must": { "match": { "message": { "query":"the quick brown", "minimum_should_match": "30%" } } }, "should": { "match_phrase": { "message": { "query": "the quick brown", "slop": 2 } } } } } } 

      但是由于 match_phrase 比较消耗性能(相对于普通的 match 而言),并且用户一般只关心结果前几页,所以可以选择用 rescore 仅对前 50 项进行处理。

      { "query" : { "match" : { "message" : { "operator" : "or", "query" : "the quick brown" } } }, "rescore" : { "window_size" : 50, "query" : { "rescore_query" : { "match_phrase" : { "message" : { "query" : "the quick brown", "slop" : 2 } } }, "query_weight" : 0.7, "rescore_query_weight" : 1.2 } } } 

    结语

    Elasticsearch 的使用实在很难穷尽,笔者在自学过程中还只能管窥一二,许多功能还没来得及探索。在写这篇文章的时候,关于导入文档的具体操作等重要内容也没有提及。不过有句话说得好,文档和代码是最好的学习资源。Elasticsearch 基于 Apache Lucene,分为 Apache 2.0 授权下的开源版、Elastic License 下的免费版,和商业版。(不过就普通使用的小规模搜索用途而言不大需要研究它的代码。)官方英文文档见: https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html。

    参考资料:

    1. 引用了来自官方文档的一些例子;

    2. What is ElasticSearch? Why ElasticSearch? Advantages of ElasticSearch!: https://medium.com/@AIMDekTech/what-is-elasticsearch-why-elasticsearch-advantages-of-elasticsearch-47b81b549f4d (写了一半查资料时看到这篇文章,深受启发。一部分内容参考了它,在此感谢并推荐。)

    9 条回复    2020-03-15 10:14:43 +08:00
    hugee
        1
    hugee  
       2020-03-14 20:28:21 +08:00
    感觉好重啊
    Heartbleed
        2
    Heartbleed  
       2020-03-14 20:32:36 +08:00 via Android
    这个是不是没有 Python 版本的..
    hantsy
        3
    hantsy  
       2020-03-14 20:59:58 +08:00
    @Heartbleed 服务器端跟你没关系的。一般使用都是客户端,各种语言的 Client 应该都有。
    CoolSpring
        4
    CoolSpring  
    OP
       2020-03-14 22:43:41 +08:00
    @Heartbleed
    关于客户端官方提供了两个 Python 库:更灵活自由的 low-level 的[elasticsearch-py]( https://github.com/elastic/elasticsearch-py)和更 Pythonic 的 high-level 的[elasticsearch-dsl-py]( https://github.com/elastic/elasticsearch-dsl-py)
    L00kback
        5
    L00kback  
       2020-03-14 23:03:16 +08:00 via Android
    顶一顶,在数据分析领域是一个很实用的工具。配合 kibana 做可视化太舒服了,非常快速,功能强大。
    est
        6
    est  
       2020-03-15 01:22:24 +08:00
    把 ES 调教好不容易。比如默认 shard 几个好?
    0dJ6Tu8Za734L89T
        7
    0dJ6Tu8Za734L89T  
       2020-03-15 02:43:31 +08:00
    我最近在集成阿里云的 open search,目的就是降低这一块的学习门槛...
    yepinf
        8
    yepinf  
       2020-03-15 10:01:58 +08:00
    ES 好像也是吃内存大户

    团队最后用了 solr
    ddup
        9
    ddup  
       2020-03-15 10:14:43 +08:00
    ES 用起来还是挺简单的,吃透还是要下一番功夫的。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     893 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 20:49 PVG 04:49 LAX 13:49 JFK 16:49
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86