ElasticSearch

官网:https://www.elastic.co/cn/
下载地址:https://www.elastic.co/cn/start

ES的概念

全文检索

    通过一个程序扫描文本中的每一个单词,针对单词建立索引,并保存该单词在文本中的位置,以及出现的次数
    用户查询时,通过之前建立好的索引来查询,将索引中单词对应的文本位置、出现的次数返回给用户,因为有了具体的文本的位置,所以就可以将具体内容读取出来。

索引 Index

    一个索引就是一个拥有几分相似特征的文档的集合。
    一个索引由一个名字来标识,必须全部是小写字母,并且当要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。

映射 Mapping

    ElasticSearch中的映射mapping用来定义一个文档。
    mapping是用来处理数据的方式和规则方面做一些限制,如某个字段的数据类型、默认值、分词器、是否被索引等等,这些都是映射里面可以设置的。

字段 Field

    相当于是数据表的字段|列

字段类型 Type

    每一个字段都应该有一个对应的类型,如:Text、Keyword、Byte等

文档 Document

    一个文档是一个可被索引的基础信息单元,类似一条记录。文档以Json格式来表示。

集群 Cluster

    一个节点是集群中的一个服务器,作为集群的一部分,它存储数据,参与集群的索引和搜索功能。

节点 Node

    一个节点可以通过配置集群名称的方式来加入一个指定的集群。默认情况下,每个节点都会被安排加入到一个叫做“elasticsearch”的集群中。
    如果在网络中启动了若干个节点,并假定它们能够互相发现彼此,它们将会自动形成并加入到一个叫做“elasticsearch”的集群中。
    在一个集群里,可以拥有若干个节点。而且,如果当前网络中没有运行任何ElasticSearch节点,这是启动一个节点,会默认创建并加入一个叫做“elasticsearch”的集群。

分片 Shards

    一个索引可以存储超过单个节点硬件的限制的大量数据。如,一个具有10亿文档的索引占据1TB的磁盘空间,而任意一个节点都没有这么大的磁盘空间;或者单个节点处理索引请求,响应太慢。
    ElasticSearch提供了将索引划分成多份的能力,这些份叫做分片。
    当创建一个索引的时候,可以指定你想要的分片的数量。
    每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。
    分片重要
        1)允许水平分割/扩展内容的容量
        2)允许在分片上进行分布式的、并行的操作,进而提高性能/吞吐量
    至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由ElasticSearch管理的,对于作为用户来说,这些都是透明的。

副本 Replicas

    在一个网络/云的环境里,失败随时都是可能发生,在某个分片/节点不知怎么的就处理离线状态,或者由于任何原因消失了,这种情况下,有个故障转移机制是非常有用并且强烈推荐的。ElasticSearch允许创建分片的一份或多份拷贝,这些拷贝叫做副本分片,或者直接叫副本。
    副本重要
        1)在分片/节点失败的情况下,提供高可用性
            分片不与原/主要分片同一个节点上。
        2)扩展搜索量/吞吐量,因为搜索可以再所有的副本上并行运行
            每个索引可以被分成多个分片。一个索引有0个或多个部分。
            一旦设置了副本,每个索引就有了主分片或者副本分片,分片和副本的数量可以在索引创建的时候指定
            在索引创建之后,可以在任何时候动态的改变副本的数量,但是不能改变分片的数量

创建及使用ES (这里直接使用腾讯云的ES)

    腾讯云ES控制台地址:https://console.cloud.tencent.com/es
    腾讯云ES创建参考文档:https://cloud.tencent.com/document/product/845/19536

1) 通过API测试访问

curl -XGET -u user:password http://xxxxxxxxx:9200

ElasticSearch

2) 通过kibana访问集群

ElasticSearch

基本操作

1) 索引 - 创建、查询、删除

格式:
    PUT /索引名称
    GET /索引名称
    DELETE /索引名称

示例:

PUT /my_es_db_index_1

GET /my_es_db_index_1

DELETE /my_es_db_index_1

2) 文档 - 添加、修改、查询、删除 (动态映射,关于映射后面的内容)

a) 添加/修改 文档

格式:
    PUT /索引名称/类型/ID

修改文档,和添加文档相同!

示例:

PUT /my_es_db_index_1/_doc/1
{
  "name": "张1",
  "sex": 1,
  "age": 21,
  "address": "广州天河公园"
}

PUT /my_es_db_index_1/_doc/2
{
  "name": "张2",
  "sex": 1,
  "age": 22,
  "address": "广州荔湾大厦"
}

PUT /my_es_db_index_1/_doc/3
{
  "name": "张3",
  "sex": 1,
  "age": 23,
  "address": "广州白云山公园"
}

PUT /my_es_db_index_1/_doc/4
{
  "name": "张4",
  "sex": 1,
  "age": 24,
  "address": "长江橘子洲头"
}

PUT /my_es_db_index_1/_doc/5
{
  "name": "张5",
  "sex": 1,
  "age": 25,
  "address": "长沙岳麓山"
}

b) 查询文档

格式:
    GET /索引名称/类型/ID

示例:

GET /my_es_db_index_1/_doc/1

GET /my_es_db_index_1/_doc/2

GET /my_es_db_index_1/_doc/3

GET /my_es_db_index_1/_doc/4

GET /my_es_db_index_1/_doc/5

如下方返回结果示例:
{
  "_index" : "my_es_db_index_1",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 2,
  "_seq_no" : 6,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "张1",
    "sex" : 1,
    "age" : 21,
    "address" : "广州天河公园"
  }
}

c) 删除文档

格式:
    DELETE /索引名称/类型/ID

示例:

DELETE /my_es_db_index_1/_doc/1

3) 批量操作

a) 批量添加文档

PUT _bulk
{"create": {"_index": "my_es_db_index_1", "_type": "_doc", "_id":6}}
{"name":"张6","sex":1,"age":26,"address":"address_6"}
{"create": {"_index": "my_es_db_index_1", "_type": "_doc", "_id":7}}
{"name":"张7","sex":1,"age":27,"address":"address_7"}
{"create": {"_index": "my_es_db_index_1", "_type": "_doc", "_id":8}}
{"name":"张8","sex":1,"age":28,"address":"address_8"}
{"create": {"_index": "my_es_db_index_1", "_type": "_doc", "_id":9}}
{"name":"张9","sex":1,"age":29,"address":"address_9"}

b) 批量删除

POST _bulk
{"delete": {"_index": "my_es_db_index_1", "_type": "_doc", "_id":6}}
{"delete": {"_index": "my_es_db_index_1", "_type": "_doc", "_id":7}}
{"delete": {"_index": "my_es_db_index_1", "_type": "_doc", "_id":8}}
{"delete": {"_index": "my_es_db_index_1", "_type": "_doc", "_id":9}}

c) 批量修改

POST _bulk
{"update": {"_index": "my_es_db_index_1", "_type": "_doc", "_id":6}}
{"doc":{"name":"张6-6666","sex":1,"age":26,"address":"address_6-66666666"}}
{"update": {"_index": "my_es_db_index_1", "_type": "_doc", "_id":7}}
{"doc": {"name":"张7-777777"}}

查询操作

1) 查询当前类型中所有的文档 _search

格式:
    DELETE /索引名称/类型/_search

示例:

GET /my_es_db_index_1/_doc/_search

// 可以省略: _doc
GET /my_es_db_index_1/_search

2) 条件查询 查询age等于22 、小于等于22、大于22

格式:
    DELETE /索引名称/_search?q=age:22
    DELETE /索引名称/_search?q=age:<=22
    DELETE /索引名称/_search?q=age:>22

示例:

GET /my_es_db_index_1/_search?q=age:22

查询结果:
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "my_es_db_index_1",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "name" : "张2",
          "sex" : 1,
          "age" : 22,
          "address" : "广州荔湾大厦"
        }
      }
    ]
  }
}

3) 范围查询 age在22 - 23之间

格式:
    DELETE /索引名称/_search?q=age[22 TO 23]

示例:

GET /my_es_db_index_1/_search?q=age[22 TO 23]

查询结果:
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "my_es_db_index_1",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "name" : "张3",
          "sex" : 1,
          "age" : 23,
          "address" : "广州白云山公园"
        }
      },
      {
        "_index" : "my_es_db_index_1",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "name" : "张2",
          "sex" : 1,
          "age" : 22,
          "address" : "广州荔湾大厦"
        }
      }
    ]
  }
}

4) 根据多个ID进行批量查询 _mget

格式:
    GET /索引名称/_mget

示例:

GET /my_es_db_index_1/_mget
{
  "ids":["2", "3"]
}

查询结果:
{
  "docs" : [
    {
      "_index" : "my_es_db_index_1",
      "_type" : "_doc",
      "_id" : "2",
      "_version" : 4,
      "_seq_no" : 8,
      "_primary_term" : 1,
      "found" : true,
      "_source" : {
        "name" : "张2",
        "sex" : 1,
        "age" : 22,
        "address" : "广州荔湾大厦"
      }
    },
    {
      "_index" : "my_es_db_index_1",
      "_type" : "_doc",
      "_id" : "3",
      "_version" : 1,
      "_seq_no" : 2,
      "_primary_term" : 1,
      "found" : true,
      "_source" : {
        "name" : "张3",
        "sex" : 1,
        "age" : 23,
        "address" : "广州白云山公园"
      }
    }
  ]
}

5) 分页查询 from=0&size=1

格式:
    DELETE /索引名称/_search?q=age[22 TO 23]&from=0&size=1

示例:

GET /my_es_db_index_1/_search?q=age[22 TO 23]&from=0&size=1

GET /my_es_db_index_1/_search?q=age[22 TO 23]&from=1&size=2

6) 查询结果只输出某些字段 _source=name,age

格式:
    DELETE /索引名称/_search?q=age[22 TO 23]&from=1&size=2&_source=name,age

示例:

GET /my_es_db_index_1/_search?q=age[22 TO 23]&from=1&size=2&_source=name,age

查询结果:
{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "my_es_db_index_1",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "name" : "张2",
          "age" : 22
        }
      }
    ]
  }
}

7) 对查询结果排序 sort=age:desc 、desc降序 / asc升序

格式:
    DELETE /索引名称/_search?q=age[22 TO 23]&sort=age:desc

示例:

GET /my_es_db_index_1/_search?q=age[22 TO 23]&sort=age:desc

GET /my_es_db_index_1/_search?q=age[22 TO 23]&sort=age:asc

文档映射(静态和动态)

    分为动态映射和动态映射。

    动态映射:
        在关系数据库中,需要事先创建数据库,然后在该数据库下创建表,并创建表字段、类型、长度、主键等,最后才能基于表插入数据。而ES中不需要定义Mapping映射,在文档写入ES时,会根据文档字段自动识别类型,这种机制称为动态映射。

JSON数据 自动推测的类型
null 没有字段被添加
true或false boolean型
小数 float型
数字 long型
日期 date或text
字符串 text
数组 由数组第一个非空值决定
JSON对象 object类型

    静态映射:
        是在ES中事先定义好映射,包含文档的各字段类型、分词器等,这种方式称之为静态映射。

获取文档映射类型

GET /my_es_db_index_1/_mapping

"properties" : {
  "address" : {
    "type" : "keyword"
  },
  "age" : {
    "type" : "long"
  },
  "name" : {
    "type" : "keyword"
  },
  "sex" : {
    "type" : "long"
  }
}

静态映射方式

创建索引及设置文档映射:

PUT /my_es_db_index_2
{
  "mappings": {
    "properties": {
      "name": {"type":"keyword", "index": true, "store": true},
      "sex": {"type":"keyword", "index": true, "store": true},
      "age": {"type":"keyword", "index": true, "store": true},
      "address": {"type":"text", "index": true, "store": true}
    }
  }
}

添加文档:

PUT /my_es_db_index_2/_doc/1
{
  "name": "张1",
  "sex": 1,
  "age": 21,
  "address": "广州天河公园"
}

查询映射类型:

GET /my_es_db_index_2/_mapping

keyword 与 text 映射类型的区别

设置为keyword映射,只能进行精确查询,不能分词查询,能聚合、排序
设置为text映射,能进行模糊查询,能分词查询,不能聚合、排序

DSL语言高级查询

    查询所有

GET /my_es_db_index_2/_doc/_search
{
  "query": {
    "match_all": {}
  }
}

1) Query

    Query方式查询,会在ES中索引的数据都会存储一个_score分值,分值越高就代表越匹配。关于某个搜索的分值计算还是很复杂的,因此也需要一定的时间。

a) 精确查询term

term查询不会对字段进行分词查询,会采用精确匹配
采用term精确查询,查询字段映射类型属于keyword

POST /my_es_db_index_1/_search
{
  "query": {
    "term": {
      "name": "张1"
    }
  }
}

b) 模糊查询match

match会根据该字段的分词器,进行分词查询,如果映射类型为keyword,就会查不到

POST /my_es_db_index_2/_search
{
  "query": {
    "match": {
      "address": "长江"
    }
  }
}

c) 多字段模糊查询

POST /my_es_db_index_2/_search
{
  "query": {
    "multi_match": {
      "query": "长江"
      , "fields": ["address", "name"]
    }
  }
}

d) 未指定字段条件查询query_string 含AND 与 OR条件

POST /my_es_db_index_2/_search
{
  "query": {
    "query_string": {
      "query": "(橘子) OR (你好)"
    }
  }
}

e) 指定字段条件查询query_string 含AND 与 OR条件

POST /my_es_db_index_2/_search
{
  "query": {
    "query_string": {
      "query": "(橘子) OR (你好)",
      "fields": ["address", "name"]
    }
  }
}

f) 范围查询

range: 范围关键字
gte:大于等于
lte:小于等于
gt:大于
lt:小于
now:当前时间

POST /my_es_db_index_2/_search
{
  "query": {
    "range": {
      "age": {
        "gte": 21,
        "lte": 22
      }
    }
  }
}

g) 分页、指定输出字段、排序

POST /my_es_db_index_2/_search
{
  "query": {
    "range": {
      "age": {
        "gte": 21,
        "lte": 25
      }
    }
  },
  "from": 0,
  "size": 3,
  "_source": ["name", "age"],
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ]
}

2) Filter

    不会计算相关性分值,也不会对接过进行排序,因此效率会高一点,查询的结果可以被缓存。

POST /my_es_db_index_2/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "age": "22"
          }
        }
      ]
    }
  }
}

通过python操作

pip install elasticsearch==7.10.1
elastic_search = Elasticsearch(["https://xxxxxxxxxxxx:9200"],
                   http_auth=('xxx', 'xxxxx'),
                   sniff_on_start=False,
                   sniff_on_connection_fail=False,
                   sniffer_timeout=None)

创建索引

PUT /my_es_db_index_3
{
  "mappings": {
    "properties": {
      "name": {"type":"keyword", "index": true, "store": true},
      "sex": {"type":"keyword", "index": true, "store": true},
      "age": {"type":"keyword", "index": true, "store": true},
      "address": {"type":"text", "index": true, "store": true}
    }
  }
}


def test_create_index(elastic_search):
    # 映射类型
    mappings = {"mappings": {
                    "properties": {
                      "name": {"type": "keyword", "index": True, "store": True},
                      "sex": {"type": "keyword", "index": True, "store": True},
                      "age": {"type": "keyword", "index": True, "store": True},
                      "address": {"type": "text", "index": True, "store": True}
                    }
                  }
                }
    # 创建索引
    res = elastic_search.index(index="my_es_db_index_3", body=mappings)
    print(res)
    
注意:这里指定type为text,不知道为什么不生效,还是为keyword,很奇怪。

删除索引

DELETE /my_es_db_index_3


def test_delete_index(elastic_search):
    res = elastic_search.indices.delete(index="my_es_db_index_3", ignore=[400, 404])
    print(res)

索引是否存在

def test_exists_index(elastic_search):
    rsp = elastic_search.indices.exists(index="my_es_db_index_3")
    print(rsp)

添加文档

PUT /my_es_db_index_3/_doc/1
{
	"name": "张1",
	"sex": 1,
	"age": 21,
	"address": "广州天河公园"
}


def test_put_document(elastic_search):
    data = {"name": "张1", "sex": 1, "age": 21, "address": "广州天河公园"}
    res = elastic_search.create(index="my_es_db_index_3", doc_type="_doc", id=1, body=data)
    print(res)

查询指定ID文档

GET /my_es_db_index_3/_doc/1


def test_get_document(elastic_search):
    rsp = elastic_search.get(index="my_es_db_index_3", doc_type="_doc", id=1)
    print(rsp)

根据多个id进行批量查询文档

GET /my_es_db_index_1/_mget
{
  "ids":["2", "3"]
}

def test_mget(elastic_search):
    data = {"ids": ["2", "3"]}
    rsp = elastic_search.mget(index="my_es_db_index_3", body=data)
    print(rsp)

查询所有文档

GET /my_es_db_index_3/_search


def test_get_all(elastic_search):
    rsp = elastic_search.search(index="my_es_db_index_3")
    print(rsp)

模糊匹配查询

POST /my_es_db_index_3/_search
{
	"query": {
		"match": {
			"address": "广州"
		}
	}
}


def test_get_match_document(elastic_search):
    data = {"query": {"match": {"address": "广州"}}}
    rsp = elastic_search.search(index="my_es_db_index_3", body=data)
    print(rsp)

删除文档

DELETE /my_es_db_index_3/_doc/1


def test_delete_document(elastic_search):
    rsp = elastic_search.delete(index="my_es_db_index_3", doc_type="_doc", id=1)
    print(rsp)

更新文档

POST _bulk
{"update": {"_index": "my_es_db_index_3", "_type": "_doc", "_id":1}}
{"doc": {"name": "张1-1", "sex": 1, "age": 21, "address": "广州天河公园"}}


def test_update_document(elastic_search):
    data = {"doc": {"name": "张1-1", "sex": 1, "age": 21, "address": "广州天河公园"}}
    rsp = elastic_search.update(index="my_es_db_index_3", doc_type="_doc", id=1, body=data)
    print(rsp)
POST /my_es_db_index_3/_search
{
  "query": {
    "match": {
      "address": "广州公园"
    }
  }
}

参考:

    腾讯课堂:https://ke.qq.com/course/3293548?taid=10771563233296748
    腾讯云ES创建参考文档:https://cloud.tencent.com/document/product/845/19536

遗留问题:上方通过python创建索引,指定type为text,但是添加后不生效

上一篇:文献学习--Deep Cooperation of CDCL and Local Search for SAT


下一篇:各种实体类的命名方式