ELASTIC SEARCH 搜索引擎

倒排索引

elastic search 使用倒排索引

  • 文档:每条数据就是一个文档
  • 词条:文档按照语义分成的词语

数据

idtitleprice
1小米手机3399
2华为手机4399
3华为充电器49
4小米手环299

分词之后的索引

词条文档id
小米1,3,4
手机1,2
华为2,3
充电器3
手环4

查询是进行分词然后去匹配分词索引,能加快返回速度

es的数据格式

文档(doc)

elasticsearch是面向文档储存的,可以是数据中的一条商品数据,一个订单信息。

文档数据会被序列化为json格式后再储存到elastic中。

[
  {
    "id": "1",
    "title": "华为手机",
    "price": 100
  },
  {
    "id": "2",
    "title": "小米手机",
    "price": 200
  }
]

索引(index)

index可以看做数据中的表,主要是区分doc的类型

安装

elastic search

docker pull elasticsearch:7.17.19
docker network create es-learn
docker run -d --name es \
-e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
-e "discovery.type=single-node" \
-v es-data:/usr/share/elasticsearch/data \
-v es-plugins:/usr/share/elasticsearch/plugins \
--privileged --network es-learn \
-p 9200:9200 -p 9300:9300 \
elasticsearch:7.17.19

kibana

docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://es:9200 \
--network=es-learn \
-p 5601:5601 kibana:7.17.19

分词器

es在创建倒排索引对文档分词时;在搜索时,需要对用户输入内容分词。但默认的分词规则对中文处理并不友好,我们在kibana的DevTool里测试:

//测试分词器
POST /_analyze
{
  "analyze": "standard",
  "text": "ES真的也太棒了"
}

es的默认分词会返回以下的结构:

{
  "tokens": [
    {
      "token": "es",
      "start_offset": 0,
      "end_offset": 2,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "真",
      "start_offset": 2,
      "end_offset": 3,
      "type": "<IDEOGRAPHIC>",
      "position": 1
    },
    {
      "token": "的",
      "start_offset": 3,
      "end_offset": 4,
      "type": "<IDEOGRAPHIC>",
      "position": 2
    },
    {
      "token": "也",
      "start_offset": 4,
      "end_offset": 5,
      "type": "<IDEOGRAPHIC>",
      "position": 3
    },
    {
      "token": "太",
      "start_offset": 5,
      "end_offset": 6,
      "type": "<IDEOGRAPHIC>",
      "position": 4
    },
    {
      "token": "棒",
      "start_offset": 6,
      "end_offset": 7,
      "type": "<IDEOGRAPHIC>",
      "position": 5
    },
    {
      "token": "了",
      "start_offset": 7,
      "end_offset": 8,
      "type": "<IDEOGRAPHIC>",
      "position": 6
    }
  ]
}

由上可以看出默认分词对中文支持不好

一般情况下我们可以引用 ik 插件作为中文分词器

安装分词器

自动安装

使用 docker exec -it es /bin/bash 进入容器后
使用 in/elasticsearch-plugin install https://github.com/infinilabs/analysis-ik/releases/tag/{version}
安装好后重启docker容器
可以直接安装插件,但在国内会比较慢

手动安装

进入本地 volume 传入下载好的文件,从新启动es便可以完成安装

分词器类型

IK 分词器包含两种类型:

  • ik_smart: 最少切分
  • ik_max_word: 最细切分

下面的返回可以更为之光的感受到两种的差距

ik_smart:

{
  "tokens": [
    {
      "token": "es",
      "start_offset": 0,
      "end_offset": 2,
      "type": "ENGLISH",
      "position": 0
    },
    {
      "token": "真的",
      "start_offset": 2,
      "end_offset": 4,
      "type": "CN_WORD",
      "position": 1
    },
    {
      "token": "也",
      "start_offset": 4,
      "end_offset": 5,
      "type": "CN_CHAR",
      "position": 2
    },
    {
      "token": "太棒了",
      "start_offset": 5,
      "end_offset": 8,
      "type": "CN_WORD",
      "position": 3
    }
  ]
}

ik_max_word:

{
  "tokens": [
    {
      "token": "es",
      "start_offset": 0,
      "end_offset": 2,
      "type": "ENGLISH",
      "position": 0
    },
    {
      "token": "真的",
      "start_offset": 2,
      "end_offset": 4,
      "type": "CN_WORD",
      "position": 1
    },
    {
      "token": "也",
      "start_offset": 4,
      "end_offset": 5,
      "type": "CN_CHAR",
      "position": 2
    },
    {
      "token": "太棒了",
      "start_offset": 5,
      "end_offset": 8,
      "type": "CN_WORD",
      "position": 3
    },
    {
      "token": "太棒",
      "start_offset": 5,
      "end_offset": 7,
      "type": "CN_WORD",
      "position": 4
    },
    {
      "token": "了",
      "start_offset": 7,
      "end_offset": 8,
      "type": "CN_CHAR",
      "position": 5
    }
  ]
}

ik分词器扩展和排除

要扩展ik分词器的词库,只需要修改一个ik分词器目录中的config目录中的ikAnalyzer.config.xml文件:


<properties>
    <comment>ik Analyzer 扩展配置</comment>
    <!--用户可以在这里配置自己的扩展词典-->
    <entry key="ext_dict">ext.dic</entry>
    <!--用户可以在这里配置自己的排除词典-->
    <entry key="ext_stopwords">stopword.dic</entry>
</properties>

索引操作

mapping属性

{
  "age": 21,
  "weight": 52.1,
  "isMarried": false,
  "info": "es学习",
  "email": "hideyoshi@hideyoshi.top",
  "score": [
    99.1,
    99.5,
    98.9
  ],
  "name": {
    "firstName": "吉",
    "lastName": "秀"
  }
}

mapping是对索引库中的文档的约束,常见的mapping属性包括

  • type:字段数据类型,重建的类型有:

    • 字符串:text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址)
    • 数值类型:long、integer、sort、byte、double、float
    • 布尔:boolean
    • 日期:date
    • 对象:object
  • index:是否创建索引,默认为true
  • analyzer:使用哪种分词器
  • properties:该字段的子字段

创建索引库

es通过restful请求操作索引库、文档。请求内容用dsl语句来表示。创建索引库和mapping的dsl语法如下:

PUT /索引库名称
{
  "mappings": {
    "properties": {
      "字段名": {
        "type": "text",
        "analyzer": "ik_smart"
      },
      "字段名2": {
        "type": "keyword",
        "index": "false"
      },
      "字段名3": {
        "type": "object",
        "properties": {
          "子字段": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

查询和删除索引库

es通过restful请求操作索引库、文档

GET /索引库名称
DELETE /索引库名称

修改索引库只允许添加字段名称,不能修改已存在的字段名

PUT /索引库名称/_mapping
{
  "properties": {
    "新字段名": {
      "type": "integer"
    }
  }
}

文档操作

es通过restful请求操作索引库、文档

GET /索引库名/_doc/文档id //新增
POST /索引库名/_doc/文档id //新建
PUT /索引库名/_doc/文档id //修改
DELETE /索引库名/_doc/文档id //删除

其中PUT请求在id不存在时是新增、在id存在是为全量修改
局部修改为

POST /索引库名/_update/文档id
{
  "doc":{
  "字段名":"新的值“
  }
}
Last modification:March 30, 2024
如果觉得我的文章对你有用,请收藏本站