01月13, 2019

Elasticsearch入门笔记

记录一下Elasticsearch的学习笔记。

全文搜索

  • 开源的Elasticsearch是目前全文搜索引擎的首选。
  • 它可以快速地储存、搜索和分析海量数据

如果使用数据库来实现搜索会怎么样?

  • 比如说商品描述字段的长度,有长达数千个,甚至数万个字符,每次都要对每条记录的所有文本进行扫描,效率非常低。
  • 不能将搜索词进行拆分。比如输入生化机,搜索不出来生化危机

全文检索是指计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程。全文搜索搜索引擎数据库中的数据。

alt

ES安装

Mac下安装Elasticsearch极简指南

这里说明一下,如果装的是最新版6.5.4,X-Pack不需要再安装,它默认集成了。

另外我装的Kibana,似乎不需要密码。

Kibana是针对Elasticsearch的开源分析及可视化平台,用来搜索、查看交互存储在Elasticsearch索引中的数据。

另外还需要装一个插件,是用来中文分词的:elasticsearch-analysis-ik

需要说明的是:elasticsearch中,内置了很多分词器(analyzers),例如standard (标准分词器)、english (英文分词)和chinese (中文分词)

但是它自带的并不是太好。

alt

上述截图,来源于这篇文章:elasticsearch ik 中文分词 安装配置

在安装完中文分词插件后,我们需要重新启动es:

brew services restart elasticsearch

核心概念

近实时

近实时,两个意思,从写入数据到数据可以被搜索到有一个小延迟(大概1秒);基于es执行搜索和分析可以达到秒级。

Cluster(集群)

集群包含多个节点,每个节点属于哪个集群是通过一个配置(集群名称,默认是elasticsearch)来决定的,对于中小型应用来说,刚开始一个集群就一个节点很正常

Node(节点)

集群中的一个节点,节点也有一个名称(默认是随机分配的),节点名称很重要(在执行运维管理操作的时候),默认节点会去加入一个名称为“elasticsearch”的集群,如果直接启动一堆节点,那么它们会自动组成一个elasticsearch集群,当然一个节点也可以组成一个elasticsearch集群

Index(索引-数据库)

索引包含一堆有相似结构的文档数据,比如可以有一个客户索引,商品分类索引,订单索引,索引有一个名称。一个index包含很多document,一个index就代表了一类类似的或者相同的document。比如说建立一个product index,商品索引,里面可能就存放了所有的商品数据,所有的商品document。

Type(类型-表)

每个索引里都可以有一个或多个type,type是index中的一个逻辑数据分类,一个type下的document,都有相同的field,比如博客系统,有一个索引,可以定义用户数据type,博客数据type,评论数据type。

每一个type里面,都会包含一堆document。

Document(文档-行)

文档是es中的最小数据单元,一个document可以是一条客户数据,一条商品分类数据,一条订单数据,通常用JSON数据结构表示,每个index下的type中,都可以去存储多个document。

Field(字段-列)

Field是Elasticsearch的最小单位。一个document里面有多个field,每个field就是一个数据字段。

mapping(映射-约束)

数据如何存放到索引对象上,需要有一个映射配置,包括:数据类型、是否存储、是否分词等。

这样就创建了一个名为blog的Index。Type不用单独创建,在创建Mapping 时指定就可以。Mapping用来定义Document中每个字段的类型,即所使用的 analyzer、是否索引等属性,非常关键等。

elasticsearch与数据库的类比

关系型数据库(比如Mysql) 非关系型数据库(Elasticsearch)
数据库Database 索引Index
表Table 类型Type
数据行Row 文档Document
数据列Column 字段Field
约束 Schema 映射Mapping

操作Index

创建索引

curl -X PUT 'http://localhost:9200/student'
  • 不能有请求体

那个像我电脑之前在iTerm折腾了一次proxy相关的东西,导致我这边会报这样的错误:

alt

然而curl百度却是好的,最终找到一个解决方案,就是带上--proxy ""

curl --proxy "" -X PUT 'http://localhost:9200/student'

alt

出于简便,下面的curl不会再带上--proxy参数。

删除索引

curl -X DELETE 'http://localhost:9200/student'

数据操作

新增文档

# 第一条
curl -X POST -H 'Content-Type:application/json' 'http://localhost:9200/student/city/1' -d '
{
    "name":"张三",
    "age":5,
    "city":"北京"
}
'

# 第二条
curl -X POST -H 'Content-Type:application/json' 'http://localhost:9200/student/city/2' -d '
{
    "name":"李四",
    "age":6,
    "city":"宁波"
}
'

# 第三条数据
curl -X POST -H 'Content-Type:application/json'  'http://localhost:9200/student/city/3' -d '
{
    "name":"赵六",
    "age":7,
    "city":"江苏"
}
'

查看文档

curl 'http://localhost:9200/student/city/1'

alt

更新记录

curl --proxy "" -X POST -H 'Content-Type:application/json' 'http://localhost:9200/student/city/1' -d '
{
    "name":"张三2",
    "age": 55,
    "city": "北京2"
}
'

删除记录

curl -X DELETE 'http://localhost:9200/student/city/1'

数据查询

查询全部

curl --proxy "" 'http://localhost:9200/student/city/_search'

alt

全文搜索

curl --proxy ""  -H 'Content-Type:application/json' 'http://localhost:9200/student/city/_search' -d '
{
  "query" : { "match" : { "name" : "张" }},
  "size": 1,
  "from": 0
}
'

通过sizefrom可以实现分页的效果。

OR

curl --proxy ""  -H 'Content-Type:application/json' 'http://localhost:9200/student/city/_search' -d '
{
  "query" : { "match" : { "name" : "张 赵" }}
}
'

alt

AND

curl --proxy ""  -H 'Content-Type:application/json' 'http://localhost:9200/student/city/_search' -d '
{
  "query" : { 
      "bool": {
      "must": [
        { "match": { "name": "赵" } },
        { "match": { "name": "六" } }
      ]
    }
  }
}
'

alt

在node中的使用

npm包里面就有指定的模块:elasticsearch

使用也很方便,直接参考一下README即可。

const elasticsearch = require('elasticsearch');
const client = new elasticsearch.Client({
  host: 'localhost:9200',
  log: 'trace',
});

client.ping({
  // ping usually has a 3000ms timeout
  requestTimeout: 1000,
}, (error) => {
  if (error) {
    console.trace('elasticsearch cluster is down!');
  } else {
    console.log('All is well');
  }
});

// 查询index索引是student的所有数据
(async () => {
  try {
    const response = await client.search({
      index: 'student'
    });
    console.log(response.hits.hits)
  } catch (error) {
    console.trace(error.message)
  }
})()
================================
运行,控制台输出结果:
================================

Elasticsearch INFO: 2019-01-15T12:27:02Z
  Adding connection to http://localhost:9200/

Elasticsearch DEBUG: 2019-01-15T12:27:02Z
  starting request {
    "method": "HEAD",
    "requestTimeout": 1000,
    "castExists": true,
    "path": "/",
    "query": {}
  }


Elasticsearch DEBUG: 2019-01-15T12:27:02Z
  starting request {
    "method": "POST",
    "path": "/student/_search",
    "query": {}
  }


Elasticsearch TRACE: 2019-01-15T12:27:02Z
  -> HEAD http://localhost:9200/

  <- 200


Elasticsearch DEBUG: 2019-01-15T12:27:02Z
  Request complete

All is well
Elasticsearch TRACE: 2019-01-15T12:27:02Z
  -> POST http://localhost:9200/student/_search

  <- 200
  {
    "took": 1,
    "timed_out": false,
    "_shards": {
      "total": 5,
      "successful": 5,
      "skipped": 0,
      "failed": 0
    },
    "hits": {
      "total": 3,
      "max_score": 1,
      "hits": [
        {
          "_index": "student",
          "_type": "city",
          "_id": "2",
          "_score": 1,
          "_source": {
            "name": "李四",
            "age": 6,
            "city": "宁波"
          }
        },
        {
          "_index": "student",
          "_type": "city",
          "_id": "1",
          "_score": 1,
          "_source": {
            "name": "张三2",
            "age": 55,
            "city": "北京2"
          }
        },
        {
          "_index": "student",
          "_type": "city",
          "_id": "3",
          "_score": 1,
          "_source": {
            "name": "赵六",
            "age": 7,
            "city": "江苏"
          }
        }
      ]
    }
  }

Elasticsearch DEBUG: 2019-01-15T12:27:02Z
  Request complete

[ { _index: 'student',
    _type: 'city',
    _id: '2',
    _score: 1,
    _source: { name: '李四', age: 6, city: '宁波' } },
  { _index: 'student',
    _type: 'city',
    _id: '1',
    _score: 1,
    _source: { name: '张三2', age: 55, city: '北京2' } },
  { _index: 'student',
    _type: 'city',
    _id: '3',
    _score: 1,
    _source: { name: '赵六', age: 7, city: '江苏' } } ]

[Done] exited with code=0 in 0.27 seconds

本文链接:www.my-fe.pub/post/elasticsearch-basic-note.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。