Elasticsearch 简介

2016.08.12/2016.08.14发布于研究暂无评论/目录

在做新主题的搜索功能时,考虑过继续使用 Google CSE,或者是最近比较流行的 Algoliasearch,不过最终选择自己搭一个 Elasticsearch,CSE 的现实和 Algolia 的配额都挺让人 egg pain. 自己搭 Elasticsearch 虽然略麻烦,但是使用起来非常灵活,另外还可以学点东西。

下面总结下 Elasticsearch 使用过程中学到的知识和迈过的坑,备忘。

因为内容较多,所以分成三篇文章:

  1. Elasticsearch 简介
  2. Elasticsearch API 介绍
  3. Elasticsearch 使用示例及 Hexo 集成

这是系列的第一篇,简要介绍了下 Elasticsearch,以下内容均基于 Debian jessie 上安装的 Elasticsearch 2.3。

Elasticsearch 简介

Elasticsearch 是一个基于 Lucene 的搜索引擎,相比 Sphinx/Coreseek,安装和配置都简单些,最重要的是文档详尽,开发也很活跃。

安装和配置

参考官方文档安装即可,没有什么麻烦的地方。

官方建议使用 Oracle 的 JDK8,命令行下载 JDK 有个麻烦的地方,必须先要接受 Oracle 的许可协议,不过可以通过设置 cookie 来解决。

wget --no-check-certificate --no-cookies \
     --header "Cookie: oraclelicense=accept-securebackup-cookie" \
     http://download.oracle.com/otn-pub/java/jdk/8u102-b14/jdk-8u102-linux-x64.tar.gz

安装好后使用默认配置就可以了,需要注意的是,为了性能考虑,Elasticsearch 建议使用相同的JVM最大和最小内存,在启动脚本配置下 ES_HEAP_SIZE 变量即可,以 systemd 为例:

$ cat /usr/lib/systemd/system/elasticsearch.service

[Service]
...
Environment=ES_HEAP_SIZE=256M
...

中文的分词需要另外安装 analyzer 插件,这里用的是 elasticsearch-analysis-ik,参照说明文档安装和配置即可。该插件允许自定义词库,但是默认的配置没有启用自带的搜狗词库。

基础概念

Elasticsearch 基于集群 (Cluster) => 节点 (Node) => 索引 (Index) => 文档类型 (Type) => 文档 (Document) 这样的层级结构来组织一个应用,每个 Cluster 由若干个 Node 组成,每个 Node 上可以并存多个 Index,每个 Index 可以定义多种 Type,然后我们实际索引的 Document 则(逻辑上)归类在各自的 Type 下。

Document 是 Elasticsearch 索引的基本单位,使用 JSON 格式表示,可以包含多个字段 (Field)。 Document 实际上存储在 Index 的分片 (Shard) 上,逻辑上划分在 Type 下。

可以把 Index 理解成 Document 的集合,它负责实际存储 Document; 而 Type 可以理解成模板 (class),它定义了 Document 的结构;Document 可以理解成符合 Type 模板的实例 (object),它保存了我们需要索引的内容。

下面是一个名为 blogs 的 Index,它有一个名为 article 的 Type,而 article 有三个字段。Index的mapping 定义了 Type 的结构,包含字段的类型,存储和索引方式等内容。

$ cat blogs-index.txt

{
    "mappings": {
       "article": {
            "properties": {
                "title": {
                    "type": "string"
                },
                "date": {
                    "type": "date",
                    "include_in_all": false
                },
                "content": {
                    "type": "string"
                }
            }
        }
    }
}

下面这条命令使用 Elasticsearch 的索引 API 来创建 Index。

curl -XPUT http://localhost:9200/blogs -d @blogs-index.txt

返回 {"acknowledged": true} 则表示索引创建成功了,然后我们就可以使用 Elasticsearch 的文档 API 在 blogs 索引上添加 article 类型的 Document:

curl -XPOST http://localhost:9200/blogs/article -d '
{
    "title": "hello world",
    "date": "2016-08-14T09:03:01",
    "content": "This is my first blog post."
}'

返回中包含 "created":true 则表示 Document 索引成功。

Analysis 处理

对于 string 类型的 Field,检索和添加 Document 到 Index 的时候,Elasticsearch 会使用 analyzer 分别对搜索关键词和 Field 进行 analysis 处理,比如字符预处理,移除 stopwords,处理英文大小写、单复数,添加同义词和分词等工作。

对中文而言,这里相对重要的是分词这一项工作,如何把搜索的关键词和 string 类型的 Field 划分成独立的词组,并不像英文一样简单。好在有一些优秀的中文 analyzer 插件可以使用。

相关度

Elasticsearch 在执行查询语句后,会对匹配的 Field 进行评分,评分越高相关度也越高,如果只查询一个 Field,该 Field 的评分就是对应的 Document 的评分,在返回搜索结果时默认会排在靠前的位置。

Elasticsearch 对 Field 的评分主要考虑以下三个方面的因素:

  • TF: 词组在 Field 中的出现频率,出现频率越高,评分越高。
  • IDF: 词组在 Index 中所有对应 Field 的出现频率,出现频率越高,词组的评分权重越低。
  • Field Length Norm: Field 长度范数,Field 长度越短,评分权重越高。

部分参数也可以影响评分,比如 boost 参数,可以在查询时提高 Field 或 Index 的权重。另外,在定义 Index 的时候,可以通过 "norms": { "enabled": false } 来禁用某个 Field 的长度对其评分的影响。

在针对多个 Field 的查询语句里,不同类型的查询语句有自己的评分规则,比如 best_fields 类型的 multi_match 语句默认使用最高的 Field 评分作为 Document 的评分,而 most_fields 类型则使用所有 Field 评分的平均值作为 Document 的评分。

评分机制比较复杂,不过好在可以使用 explain API 查看特定查询语句下某个 Document 的评分明细。

#elasticsearch#全文检索#总结

评论