• elasticsearch使用


    一. 安装java环境与elasticsearch、kibana

    ​ 首先要求jdk为1.8及以上,这里elasticsearch(kibana同理,尽量保证elasticsearch版本一致,安装和启动方式也是一样的)版本采用6.5.4。

    ​ elasticsearch简介:https://baike.baidu.com/item/elasticsearch/3411206?fr=aladdin

    ​ elasticsearch官网:https://www.elastic.co/cn/downloads/

    ​ 点击下载,之后下拉选择历史版本past releases

    ​ 最后点击download即可

    ​ java环境配置看该博客:https://www.cnblogs.com/Neeo/articles/10368280.html

    ​ 安装完毕后如果没有出现错误,解压elasticsearch,然后进入其bin目录,双击打开其中的elasticsearch.bat文件即可,随后访问127.0.0.1:9200,如果能看到返回的json数据,代表配置成功。(其中9200是节点监听的断开,而9300是集群默认监听的端口)。

    ​ 未能正常启动原因

    二. elasticsearch、kibana的部分文件说明

    ​ 1. 解压后的config中的elasticsearch.yml就是ES的配置文件,这用Notepad打开。

    同目录的jvm.options是虚拟机jrel的配置。

    同目录的log4j2.properties是日志的配置,可以配置日志的输出、级别等信息,一般不会修改。(log4j是Apache的一个框架,用于控制日志)

    1. Kibana目录下的config中的kibana.yml存放其配置文件。

    三. Kibana的Dev tools中ES的简单命令

    ​ 数据准备

    PUT s18/doc/2
    {
      "name":"yangtao",
      "age": 18,
      "tags":"浪",
      "b":"19970521",
      "sex": "男"
    }
    
    
    PUT s18/doc/1
    {
      "name":"egon",
      "age": 20,
      "tags":"认真学习",
      "b":"19970781",
      "sex": "男"
    }
    
    
    PUT s18/doc/3
    {
      "name":"sybil",
      "age": 3,
      "tags":"认真学习",
      "b":"19971216",
      "sex": "女"
    }

    '索引/类型/文档' 的格式
    #增 PUT  如果PUT对的数据已存在,那么会进行更新的操作,但是PUT时传的参数是什么,更新之后的数据就是什么,所以需要填写所有的字段
        PUT s18/doc/1   #新增索引s18/doc/1  s18是_index,1是该数据的文档,doc是Type
        {
            "name":"sybil",
            "skill":"fly",
            "hobby":"sleep",
            "tags":"beautiful"
        }
        
    #删  DELETE
        DELETE s18  #删除索引(数据库)
        DELETE s18/doc/1  #删除索引s18下type是doc,文档是1的数据
        DELETE s18/doc/_search?q=tags:beautiful  #这是错误的删除方式,要使用search的方式删除需要使用POST
            
    #查  GET
        GET s18/doc/1  #查文档为1的数据
        GET s18/doc/_search  #查所有
        GET s18/doc/_search?q=name:sybil  #查名字叫sybil的
    
    #更新指定字段POST,或配合search删除
        POST s18/doc/1/_update
        {
          "doc":{  # 需要指定type,相当于指定表名
            "tags":"美丽冻人"
          }
        }
        
        POST s18/doc/_delete_by_query?q=age:18  #删除年龄为18的数据,不过不推荐使用该方式
     
    #查询的两种方式
        1.查询字符串 query string
            GET s18/doc/_search?q=age:18
                
        2. DSL 结构化查询
            GET s18/doc/_search
            {
                "query":{
                    "match":{
                        "age":18
                    }
                }
            }
            
            GET s18/doc/_search
            {
                "query":{
                    "match_all":{}  #因为是查所有,不需要参数
                }
            }
            
    
    1. GET s18/_mapping

    1. GET s18/_settings

    2. GET s18

    四. ES的复杂查询

    1.排序sort、分页、布尔查询bool

    #排序 sort  不是所有的字段都能排序,比如名字
        GET s18/doc/_search
            {
                "query":{
                    "match_all":{}
                },
                "sort": [  #排序
                    {
                        "age":{
                            "order": "asc" #升序,desc降序
                        }
                    }
                ]
            }
            
    #分页 内部会先排好序,保证翻页后不会出现已经返回过的数据
        GET s18/doc/_search
        {
            "query":{
                   "match_all":{}
               },
            "from": 0,  #从0条开始
            "size": 2  #返回2条数据
        }
    
    #布尔查询bool: should(or)  must(and)  must_not(not),must_not
        GET s18/doc/_search
        {
            "query": {
                "bool": {
                    "should": [  #名字是sybil或者年龄18岁
                        {
                            "match": {
                                "name": "sybil"
                            }
                        },
                        {
                            "match": {
                                "age": "18"
                            }
                        }
                    ]
                }
            }
        }
        
        '查询性别是男的,年龄18'
        GET s18/doc/_search
        {
            "query": {
                "bool":{
                    "must": [
                        {
                            "match": {
                                "age": "18"
                            }
                        },
                        {
                             "match": {
                            "sex": "男"
                            }
                        }
                    ]
                }
            }
        }
        
    #查询年龄大于19岁的男的  filter尽量用must配合,避免脏数据
        GET s18/doc/_search
        {
            "query": {
                "bool": {
                    "must": [
                        {"match": {
                            "sex": "男"
                        }}
                    ],
                    "filter": {
                        "range": {
                            "age": {
                                "gte": 19,
                                "lte": 20
                            }
                        }
                    }
                }
            }
        }
        

    2.高亮查询highlight

    #查询name是sybil的文档
    #高亮查询,查询name是sybil的文档,查询的结果需要在前端才能体现高亮,因为是标签的效果
    GET s18/doc/_search
    {
      "query": {
        "match": {
          "name": "sybil"
        }
      },
      "highlight": {
        "fields": {
          "name": {}  #查询的结果用<em>标签包裹
        }
      }
    }
    
    GET s18/doc/_search
    {
      "query": {
        "match": {
          "name": "sybil"  #会将我们这里定义的字段高亮显示
        }
      },
      "highlight": {  #可以使用pre_tags与post_tags自定义标签
        "pre_tags": "<b style='color:red;font-size:20px'>", 
        "post_tags": "<>", 
        "fields": {
          "name": {}  #这里指定字段后空着即可
        }
      }
    }

    3.结果过滤_source

    #过滤出查询结果中想要的字段
    GET s18/doc/_search
    {
      "query": {
        "match": {
          "name": "sybil"
        }
      },
      "_source": "name"  #单个字段
    }
    
    GET s18/doc/_search
    {
      "query": {
        "match": {
          "name": "sybil"
        }
      },
      "_source": ["name", "age"]  #多个字段
    }
    

    4.聚合查询

    #sum,查询所有男生的年龄
    GET s18/doc/_search
    {
      "query": {
        "match": {
          "sex": "男"
        }
      },
      "aggs": {
        "my_sum": {  #这是查询结果的键,可以自定义
          "sum": {  #这是聚合的方法
            "field": "age"  #指定聚合的依据
          }
        }
      }
    }
    
    #查询最大年龄的男生
    GET s18/doc/_search
    {
      "query": {
        "match": {
          "sex": "男"
        }
      },
      "aggs": {
        "my_max": {
          "max": {
            "field": "age"
          }
        }
      }
    }
    
    #查询最小年龄的男生
    GET s18/doc/_search
    {
      "query": {
        "match": {
          "sex": "男"
        }
      },
      "aggs": {
        "my_min": {
          "min": {
            "field": "age"
          }
        }
      }
    }
    
    #查询男生的平均年龄
    GET s18/doc/_search
    {
      "query": {
        "match": {
          "sex": "男"
        }
      },
      "aggs": {
        "my_avg": {
          "avg": {
            "field": "age"
          }
        }
      }
    }
    
    #分组,根据年龄,0-10,,0-20
    GET s18/doc/_search
    {
      "query": {
        "match": {
          "sex": "男"
        }
      },
      "aggs": {
        "my_group": {  #分组名称
          "range": {
            "field": "age",
            "ranges": [
              {  
                "from": 0,  #[0, 10)
                "to": 10
              },
              {
                "from": 10,
                "to": 20
              },
              {
                "from": 20,
                "to": 30
              }
            ]
          }
        }
      }
    }
    
    #分组,根据年龄,0-10,,0-20, 对每组年龄求和
    GET s18/doc/_search
    {
      "query": {
        "match": {
          "sex": "男"
        }
      },
      "aggs": {
        "my_group": {
          "range": {
            "field": "age",
            "ranges": [
              {
                "from": 0,
                "to": 10
              },
              {
                "from": 10,
                "to": 20
              },
              {
                "from": 20,
                "to": 30
              }
            ]
          },
          "aggs": {
            "my_sum": {
              "sum": {
                "field": "age"
              }
            }
          }
        }
      }
    }

    5. ES的mapping映射

    #自定义索引的映射
    PUT s2
    {
      "mappings": {
        "doc":{  #类型
          "properties":{  #文档的属性
            "name":{
              "type":"text"
            },
            "age":{
              "type":"long"
            },
            "desc":{
              "type":"text"
            }
          }
        }
      }
    }
    
    #如果给该索引加文档时,额外增加了字段,那么mappings会自动增加该字段,使其能够成为查询条件
    GET s2/_mapping
    PUT s2/doc/2
    {
      "name":"catmao",
      "age":30,
      "desc":"beautiful",
      "skill":"sleep"
    }
    GET s2/_mapping  #再次执行会发现字段多了skill
    
    #这是由mappings的dynamic的三种状态,三种状态时,均可以缺省字段
    dynamic为true时特征如上。
    
    dynamic为false时,PUT添加的数据有额外字段时,Mapping不会自动添加,该字段也无法成为查询的条件。
    
    dynamic为strict时,添加的数据不能有额外的字段,会直接报错
        PUT s6
        {
          "mappings": {
            "doc":{
              "dynamic":"strict",
              "properties":{
                "name":{
                  "type":"text"
                }
              }
            }
          }
        }
    #mapping的ignore_above,不会为超过该设定字符长度的字符串设定索引与存储,即无法成为有效的查询条件,仅对type为keyword的字段有效。
    https://www.cnblogs.com/Neeo/articles/10789701.html
        PUT s7
        {
          "mappings": {
            "doc":{
              "properties":{
                "title":{
                  "type":"keyword",
                  "ignore_above":10
                }
              }
            }
          }
        }
    
        PUT s7/doc/2
        {
          "title":"从手机、平板电脑、路由器"
        }
        PUT s7/doc/1
        {
          "title":"1234567"
        }
        GET s7/doc/_search
        {
          "query": {
            "match": {
              "title": "1234567"
            }
          }
        }
        
    #mappings参数之index,设置为false后,ES不会为该字段建立索引,其实是不会做分词
    #mappings的index参数
        PUT s8
        {
          "mappings": {
            "doc":{
              "properties":{
                "t1":{
                  "type":"text",
                  "index":"true"
                },
                "t2":{
                  "type":"text",
                  "index":"false"
                }
              }
            }
          }
        }
    
        PUT s8/doc/1
        {
          "t1":"论母猪的厂前保养",
          "t2":"论母猪的厂后保养"
        }
    
        GET s8/doc/_search
        {
          "query": {
            "match": {
              "t2": "母猪"
            }
          }
        }
        
    #mappings的copy_to,把一个字段的值复制给另一个,可以减少一次查询的次数
        PUT s9
        {
          "mappings": {
            "doc":{
              "properties":{
                "t1":{
                  "type":"text",
                  "copy_to":"full_name"  #复制给多个字段 ["f1", "f2"]
                },
                "t2":{
                  "type":"text",
                  "copy_to":"full_name"
                },
                "full_name":{
                  "type":"text"
                }
              }
            }
          }
        }
    
        PUT s9/doc/1
        {
          "t1":"xxx",
          "t2":"ooo"
        }
    
        GET s9/doc/_search
        {
          "query": {
            "match": {
              "full_name": "xxx"
            }
          }
        }

    6.嵌套属性

    #嵌套类型
        PUT w1
        {
          "mappings": {
            "doc":{
              "properties":{
                "name":{
                  "type":"text"
                },
                "age":{
                  "type":"long"
                },
                 "info":{  #info字段嵌套两个字段
                    "properties":{
                      "addr":{
                        "type":"text"
                      },
                      "tel":{
                        "type":"long"
                      }
                    }
            }
              }
            }
          }
        }
    
        PUT w1/doc/1  #插入一条数据
        {
          "name":"tom",
          "age":18,
          "info":{  
            "addr":"北京",
            "tel":"10010"
          }
        }
    
        GET w1/doc/_search
        {
          "query": {
            "match": {
              "info.tel": "10010"  #以嵌套字段的属性为查询条件时,直接点语法即可
            }
          }
        }

    7.settings设置主从分片

    #主分片一旦设置无法更改,复制分片可以
    PUT w2
    {
      "mappings": {
        "doc":{
          "properties":{
            "title":{
              "type":"text"
            }
          }
        }
      }, 
      "settings": {  #通过settings设置
        "number_of_shards": 3,  #主分片数量,默认为5
        "number_of_replicas": 3  #复制分片数量,默认为1
      }
    }
    
    GET w2

    8.match系列

    博客地址https://www.cnblogs.com/Neeo/articles/10578482.html

    #数据准备
    PUT t1/doc/1
    {
      "title":"中国是世界上人口最多的国家"
    }
    PUT t1/doc/2
    {
      "title":"美国是世界上军事实力强大多的国家"
    }
    PUT t1/doc/3
    {
      "title":"北京是中国 的首都"
    }

    ​ 使用match查询“中国”

    #会发现美国也包含在其中,这是因为match内部会散列分词,内部是采用标准的分析器,中国会分为中和国
    GET t1/doc/_search
    {
      "query": {
        "match": {
          "title": "中国"
        }
      }
    }

    ​ 我们想把中国当成一个短语,需要采用match_phrase

    #这样就不好分词,把中国当成一个短语去查询
    GET t1/doc/_search
    {
      "query": {
        "match_phrase": {
          "title": "中国"
          "slop": 1  #该参数可以指定分词的间隔
        }
      }
    }

    ​ 最左前缀查询match_phrase_prefix

    PUT t2/doc/1
    {
      "title":"beautiful girl"
    }
    
    PUT t2/doc/2
    {
      "title":"beautiful so"
    }
    
    GET t2/doc/_search
    {
      "query": {
        "match_phrase_prefix": {
          "title": "bea"  #只要有单词以bea开头
        }
      }
    }

    ​ multi_match多字段查询,可以完成match_phrase和match_phrase_prefix的工作,使用很灵活。

    PUT t3/doc/1
    {
      "t1":"beautiful girl",
      "t2":"beautiful so"
    }
    
    #查找字段t1和t2都包含beautiful的文档
    GET t3/doc/_search
    {
      "query": {
        "multi_match": {
          "query": "beautiful",
          "fields": ["t1", "t2"]
        }
      }
    }

    五. elasticsearch分析数据的过程漫谈

    详见博客https://www.cnblogs.com/Neeo/p/10304892.html,附带安装ik分词

    5.1 ik安装的问题

    5.2 ik分词的测试

    #ik分词的测试
    GET _analyze
    {
      "analyzer": "standard",
      "text":"上海自来水来自海上"
    }
    
    GET _analyze
    {
      "analyzer": "ik_smart",
      "text":"上海自来水来自海上"
    }
    
    #粒度更细,一般存储时建议使用粒度粗的(意义更大),ik_max_word会将文档做最细粒度的拆分
    GET _analyze
    {
      "analyzer": "ik_max_word",
      "text":"上海自来水来自海上"
    }
    

    六. python操作Elasticsearch

    6.1 python连接 ES

    ​ doc_type默认是doc,所以可以不写,不过建议都写上,以防万一

    '1. 安装elasticsearch模块'
    pip install elasticsearch
    # 豆瓣源
    pip install -i https://pypi.doubanio.com/simple/             elasticsearch
            
    '2. 连接的方式'
    from elasticsearch import  Elasticsearch
    # es = Elasticsearch()    # 默认连接本地elasticsearch
    # es = Elasticsearch(['127.0.0.1:9200'])  # 连接本地9200端口
    es = Elasticsearch(
        ["192.168.1.10", "192.168.1.11", "192.168.1.12"], # 连接集群,以列表的形式存放各节点的IP地址
        sniff_on_start=True,    # 连接前测试
        sniff_on_connection_fail=True,  # 节点无响应时刷新节点
        sniff_timeout=60    # 设置超时时间
    )
    
    '3. 配置忽略响应状态码'
    es = Elasticsearch(['127.0.0.1:9200'],ignore=400)  # 忽略返回的400状态码
    es = Elasticsearch(['127.0.0.1:9200'],ignore=[400, 405, 502])  # 以列表的形式忽略多个状态码
    
    '4. 简单的示例'
    from elasticsearch import  Elasticsearch
    es = Elasticsearch()    # 默认连接本地elasticsearch
    # print(es.ping())  #可以用该方法查看是否连接成功,如果群集已启动,则返回True,否则返回False
    print(es.index(index='p1', doc_type='doc', id=1, body={'name': "sybil", "age": 18}))  #index方法,如果索引存在则更新,否则增加新记录
    print(es.get(index='p1', doc_type='doc', id=1))

    6.2 python操作ES

    # search方法使用的较多,因为可以跟复杂查询
    '对返回的信息的几种过滤方法(过滤出想要显示的信息)'
    body = {
        "query": {
            "match": {
                "name": "lou22"
            }
        }
    }
    # 返回的是一个大字典
    print(es.search(index='p1', body=body))
    # 可以使用filter_path过滤出其中想要的信息
    print(es.search(index='p1', body=body, filter_path=['hits.hits']))
    # 查询出来的信息主要保存在_source中  {'hits': {'hits': [{'_source': {'name': 'lou22'}}]}}
    print(es.search(index='p1', body=body, filter_path=['hits.hits._source']))
    # 也可以指定多个要显示的信息 {'hits': {'total': 1, 'hits': [{'_source': {'name': 'lou22'}}]}}
    print(es.search(index='p1', body=body, filter_path=['hits.hits._source', 'hits.total']))
    # 可以用*指定返回hits下所有的内容  *是语法,表示所有
    print(es.search(index='p1', body=body, filter_path=['hits.*']))
    # 可以用*指定返回hits下的hits中所有的内容
    print(es.search(index='p1', body=body, filter_path=['hits.hits._*']))
    
    
    '过滤出结果中想要的字段,_source'
    print(es.search(index='py3', doc_type='doc', body={"query": {"match":{"age": 20}}}))  # 一般查询
    print(es.search(index='py3', doc_type='doc', body={"query": {"match":{"age": 19}}},_source=['name', 'age']))  # 结果字段过滤
    print(es.search(index='py3', doc_type='doc', body={"query": {"match":{"age": 19}}},_source_exclude  =[ 'age']))  #除了age字段之外的所有字段都要
    print(es.search(index='py3', doc_type='doc', body={"query": {"match":{"age": 19}}},_source_include =[ 'age']))  #只要age字段,同_source差不多

    get_source直接返回数据字典

    # 直接返回数据字典  {'name': 'lou22'}
    print(es.get_source(index='p1', doc_type='doc', id=1))

    count统计查询结果的个数

    # 新建几条数据
    for i in range(2, 11):
        print(es.index(index='p1', doc_type='doc', body={"name": "lou%s" % i}))
    
    # 指定用于查询的方式
    body = {
        "query": {
            "match": {
                "name": "lou2"
            }
        }
    }
    #查询回来的结果就是字典,可以采用字典的操作方式
    print(es.count(index='p1', doc_type='doc', body=body))['count']  # 1
    print(es.count(index='w2'))  # {'count': 6, '_shards': {'total': 5, 'successful': 5, 'skipped': 0, 'failed': 0}}
    print(es.count(index='w2', doc_type='doc')) # {'count': 6, '_shards': {'total': 5, 'successful': 5, 'skipped': 0, 'failed': 0}}

    es.create创建索引(索引不存在的话)并新增一条数据,索引存在仅新增(只能新增,重复执行会报错

    #其实内部调用了es.index,一般不使用create方法
    print(es.create(index='py3', doc_type='doc', id='1', body={"name": '王五', "age": 20}))
    print(es.get(index='py3', doc_type='doc', id='1'))

    es.deletees.delete_by_query

    #es.delete,删除指定的文档。比如删除文章id为4的文档,但不能删除索引,如果想要删除索引,还需要es.indices.delete来处理
    print(es.delete(index='py3', doc_type='doc', id='4'))
    
    #es.delete_by_query,删除与查询匹配的所有文档
    print(es.delete_by_query(index='py3', doc_type='doc', body={"query": {"match":{"age": 20}}}))

    es.existses.info

    # es.exists,查询elasticsearch中是否存在指定的文档,返回一个布尔值
    print(es.exists(index='py3', doc_type='doc', id='1'))
    
    #es.info,获取当前集群的基本信息,一般使用kibana查看,因为比较直观
    print(es.info())

    6.3 es.indices对索引的操作

    es.indices.create在Elasticsearch中创建索引,用的最多

    body = {
        "mappings": {
            "doc": {
                "dynamic": "strict",  #设置严格模式
                "properties": {
                    "title": {
                        "type": "text",
                        "analyzer": "ik_max_word"
                    },
                    "url": {
                        "type": "text"
                    },
                    "action_type": {
                        "type": "text"
                    },
                    "content": {
                        "type": "text"
                    }
                }
            }
        }
    }
    es.indices.create('py4', body=body)

    es.indices.analyze,返回分词结果

    es.indices.analyze(body={'analyzer': "ik_max_word", "text": "皮特和茱丽当选“年度模范情侣”Brad Pitt and Angelina Jolie"})

    es.indices.delete,在Elasticsearch中删除索引

    print(es.indices.delete(index='py4'))
    print(es.indices.delete(index='w3'))    # {'acknowledged': True}

    es.indices.put_alias,为一个或多个索引创建别名,查询多个索引的时候,可以使用这个别名

    print(es.indices.put_alias(index='py4', name='py4_alias'))  # 为单个索引创建别名
    print(es.indices.put_alias(index=['py3', 'py2'], name='py23_alias'))  # 为多个索引创建同一个别名,联查用

    es.indices.delete_alias,删除一个或多个别名

    print(es.indices.delete_alias(index='alias1'))
    print(es.indices.delete_alias(index=['alias1, alias2']))

    es.indices.get_mapping,检索索引或索引/类型的映射定义

    print(es.indices.get_mapping(index='py4'))

    es.indices.get_settings,检索一个或多个(或所有)索引的设置

    print(es.indices.get_settings(index='py4'))

    es.indices.get,允许检索有关一个或多个索引的信息

    print(es.indices.get(index='py2'))    # 查询指定索引是否存在
    print(es.indices.get(index=['py2', 'py3']))

    es.indices.get_alias,检索一个或多个别名

    print(es.indices.get_alias(index='py2'))
    print(es.indices.get_alias(index=['py2', 'py3']))

    es.indices.get_field_mapping,检索特定字段的映射信息

    print(es.indices.get_field_mapping(fields='url', index='py4', doc_type='doc'))
    print(es.indices.get_field_mapping(fields=['url', 'title'], index='py4', doc_type='doc'))

    其他

    # es.indices.delete_alias,删除特定别名。
    # es.indices.exists,返回一个布尔值,指示给定的索引是否存在。
    # es.indices.exists_type,检查索引/索引中是否存在类型/类型。
    # es.indices.flus,明确的刷新一个或多个索引。
    # es.indices.get_field_mapping,检索特定字段的映射。
    # es.indices.get_template,按名称检索索引模板。
    # es.indices.open,打开一个封闭的索引以使其可用于搜索。
    # es.indices.close,关闭索引以从群集中删除它的开销。封闭索引被阻  止进行读/写操作。
    # es.indices.clear_cache,清除与一个或多个索引关联的所有缓存或特定缓存。
    # es.indices.put_alias,为特定索引/索引创建别名。
    # es.indices.get_uprade,监控一个或多个索引的升级程度。
    # es.indices.put_mapping,注册特定类型的特定映射定义。
    # es.indices.put_settings,实时更改特定索引级别设置。
    # es.indices.put_template,创建一个索引模板,该模板将自动应用于创建的新索引。
    # es.indices.rollove,当现有索引被认为太大或太旧时,翻转索引API将别名转移到新索引。API接受单个别名和条件列表。别名必须仅指向单个索引。如果索引满足指定条件,则创建新索引并切换别名以指向新别名。
    # es.indices.segments,提供构建Lucene索引(分片级别)的低级别段信息

    6.4 Cluster 集群相关

    es.cluster.get_settigns,获取集群设置

    print(es.cluster.get_settings())

    es.cluster.health,获取有关群集运行状况的非常简单的状态

    print(es.cluster.health())

    es.cluster.state,获取整个集群的综合状态信息

    print(es.cluster.state())

    es.cluster.stats,返回群集的当前节点的信息

    print(es.cluster.stats())

    6.5 Node 节点相关

    es.nodes.info,返回集群中节点的信息

    print(es.nodes.info())  # 返回所节点
    print(es.nodes.info(node_id='node1'))   # 指定一个节点
    print(es.nodes.info(node_id=['node1', 'node2']))   # 指定多个节点列表

    es.nodes.stats,获取集群中节点统计信息

    print(es.nodes.stats())
    print(es.nodes.stats(node_id='node1'))
    print(es.nodes.stats(node_id=['node1', 'node2']))

    es.nodes.hot_threads,获取指定节点的线程信息

    print(es.nodes.hot_threads(node_id='node1'))
    print(es.nodes.hot_threads(node_id=['node1', 'node2']))

    es.nodes.usage,获取集群中节点的功能使用信息

    print(es.nodes.usage())
    print(es.nodes.usage(node_id='node1'))
    print(es.nodes.usage(node_id=['node1', 'node2']))

    6.6 Cat 一种查询方式

    es.cat.aliases,返回别名信息

    #name要返回的以逗号分隔的别名列表。
    #formatAccept标头的简短版本,例如json,yaml
    print(es.cat.aliases(name='py23_alias'))
    print(es.cat.aliases(name='py23_alias', format='json'))

    es.cat.allocation,返回分片使用情况

    print(es.cat.allocation())
    print(es.cat.allocation(node_id=['node1']))
    print(es.cat.allocation(node_id=['node1', 'node2'], format='json'))

    es.cat.count,Count提供对整个群集或单个索引的文档计数的快速访问

    print(es.cat.count())  # 集群内的文档总数
    print(es.cat.count(index='py3'))  # 指定索引文档总数
    print(es.cat.count(index=['py3', 'py2'], format='json'))  # 返回两个索引文档和

    es.cat.fielddata,基于每个节点显示有关当前加载的fielddata的信息。有些数据为了查询效率,会放在内存中,fielddata用来控制哪些数据应该被放在内存中,而这个es.cat.fielddata则查询现在哪些数据在内存中,数据大小等信息

    print(es.cat.fielddata())
    print(es.cat.fielddata(format='json', bytes='b'))
    #bytes显示字节值的单位,有效选项为:'b','k','kb','m','mb','g','gb','t','tb' ,'p','pb'
    #formatAccept标头的简短版本,例如json,yaml

    es.cat.health,从集群中health里面过滤出简洁的集群健康信息

    print(es.cat.health())
    print(es.cat.health(format='json'))

    es.cat.help,返回es.cat的帮助信息

    print(es.cat.help())

    es.cat.indices,返回索引的信息

    print(es.cat.indices())
    print(es.cat.indices(index='py3'))
    print(es.cat.indices(index='py3', format='json'))

    es.cat.master,返回集群中主节点的IP,绑定IP和节点名称

    print(es.cat.master())
    print(es.cat.master(format='json'))

    es.cat.nodeattrs,返回节点的自定义属性

    print(es.cat.nodeattrs())
    print(es.cat.nodeattrs(format='json'))

    es.cat.nodes,返回节点的拓扑,这些信息在查看整个集群时通常很有用,特别是大型集群。我有多少符合条件的节点

    print(es.cat.nodes())
    print(es.cat.nodes(format='json'))

    es.cat.plugins,返回节点的插件信息

    print(es.cat.plugins())
    print(es.cat.plugins(format='json'))

    es.cat.segments,返回每个索引的Lucene有关的信息

    print(es.cat.segments())
    print(es.cat.segments(index='py3'))
    print(es.cat.segments(index='py3', format='json'))

    es.cat.shards,返回哪个节点包含哪些分片的信息

    print(es.cat.shards())
    print(es.cat.shards(index='py3'))
    print(es.cat.shards(index='py3', format='json'))

    es.cat.thread_pool,获取有关线程池的信息

    print(es.cat.thread_pool())

    6.7 Snapshot 快照相关

    # es.snapshot.create,在存储库中创建快照。
        repository 存储库名称。
        snapshot快照名称。
        body快照定义。
    # es.snapshot.delete,从存储库中删除快照。
    # es.snapshot.create_repository。注册共享文件系统存储库。
    # es.snapshot.delete_repository,删除共享文件系统存储库。
    # es.snapshot.get,检索有关快照的信息。
    # es.snapshot.get_repository,返回有关已注册存储库的信息。
    # es.snapshot.restore,恢复快照。
    # es.snapshot.status,返回有关所有当前运行快照的信息。通过指定存储库名称,可以将结果限制为特定存储库。
    # es.snapshot.verify_repository,返回成功验证存储库的节点列表,如果验证过程失败,则返回错误消息

    6.8 Task 任务相关

    # es.tasks.get,检索特定任务的信息。
    # es.tasks.cancel,取消任务。
    # es.tasks.list,任务列表

    七. python使用ES搜索小例子

    7.1 settings.py中指定连接数据库

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'test_es',
            'HOST': '127.0.0.1',
            'PORT': 3306,
            'USER': 'root',
            'PASSWORD': 'root'
        }
    }

    7.2 models.py中建立模型表,并同步至数据库

    from django.db import models
    
    
    class Car(models.Model):
        title = models.CharField(max_length=255)
        summary = models.CharField(max_length=255)
        img_url = models.CharField(max_length=255, null=True)
        tags = models.CharField(max_length=255)
        a_url = models.CharField(max_length=255)
    

    ​ 随后执行数据库迁移命令

    python manage.py makemigrations
    python manage.py migrate

    7.3 新建一个spider.py文件,配置django环境,爬取数据

    #!/usr/bin/env python
    import os
    
    if __name__ == "__main__":
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "review_django.settings")
        import django
        django.setup()
        import requests
        from bs4 import BeautifulSoup
        from concurrent.futures import ThreadPoolExecutor
        from app01 import models
    
        def work(k):
            response = requests.get(url='https://www.autohome.com.cn/all/{}/#liststart'.format(k))
            response.encoding = 'GBK'
            soup_obj = BeautifulSoup(response.text, 'html.parser')
            div_obj = soup_obj.find(name='div', attrs={"id": "auto-channel-lazyload-article"})
            li_list = div_obj.find_all(name='li')
            for i in li_list:
                no_obj = i.find(name='h3')
                if not no_obj: continue
                title = i.find(name='h3').text
                summary = i.find(name='p').text
                a = 'https:' + i.find(name='a').get('href')
                img = 'https:' + i.find(name='img').get('src')
                tags = a.split('/', 4)[3]
                print(response.url, title, tags)
                print(summary, img)
                models.Car.objects.create(
                    title=title,
                    summary=summary,
                    tags=tags,
                    img_url=img,
                    a_url=a
                )
    
        def spider():
            t = ThreadPoolExecutor(10)
            for k in range(1, 60):
                t.submit(work, k)
            t.shutdown()
    
        spider()
    

    7.4 urls.py中配置路由

    from django.conf.urls import url
    from app01 import views
    
    urlpatterns = [
        # 用于简单显示一个页面,同时展示用户搜索的内容
        url(r'index', views.index),
        # 将数据库数据写入es
        url(r'es', views.es2)
    ]

    7.5 views.py中视图函数

    from django.shortcuts import render, HttpResponse
    from django.http import JsonResponse
    from elasticsearch import Elasticsearch
    from elasticsearch import helpers
    from app01 import models
    
    
    # 实例化一个ES对象
    es = Elasticsearch()
    
    # Create your views here.
    
    
    def filter(search_msg):
    
        body = {
            "size": 100,  # 返回一百条数据
            "query": {
                "match": {
                    "title": search_msg  # 从标题中查找输入的关键字
                }
            },
            "highlight": {  # 内容高亮显示,使用pre_tags与post_tags定义标签,默认是em标签
                "pre_tags": "<b style='color:red;font-size:24px'>",
                "post_tags": "</b>",
                "fields": {
                    "title": {}  # 将标题高亮显示
                }
            },
        }
        # 存储es搜索的结果
        res = es.search(index='s18', body=body)
        # print(res)
        return res
    
    
    def index(request):
        if request.method == "POST":
            search_msg = request.POST.get('search_msg')
            res = filter(search_msg)
            # 将es搜索的结果返回
            return JsonResponse(res)
        return render(request, 'search.html', locals())
    
    
    def es2(request):
        body = {
            "mappings": {
                "doc": {
                    "properties": {
                        "title": {
                            "type": "text"
                        },
                        "summary": {
                            "type": "text"
                        },
                        "a_url": {
                            "type": "keyword"
                        },
                        "img_url": {
                            "type": "keyword"
                        },
                        "tags": {
                            "type": "text"
                        }
                    }
                }
            }
        }
        # es.indices.create(index='s18', body=body)
        # print(es.indices.get_mapping())
        query_list = models.Car.objects.all()
        # 定义写入es的数据格式,使用生成器,减轻内存压力
        action = ({
            "_index": "s18",  # 索引,相当于指定数据库,不存在则创建
            "_type": "doc",  # 类型,相当于指定表,不存在则创建
            "_source": {  # 指定要写入的内容
                "title": i.title,
                "summary": i.summary,
                "a_url": i.a_url,
                "img_url": i.img_url,
                "tags": i.tags
            }
        }
            for i in query_list
        )
        # helpers会使用java虚拟机帮我们进行该任务
        helpers.bulk(es, action)
        return HttpResponse('ok es')
    

    7.6 templates文件下写的search.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
        <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    </head>
    <body>
    <nav class="navbar navbar-default">
      <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Brand</a>
        </div>
    
        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
            <li><a href="#">Link</a></li>
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
              <ul class="dropdown-menu">
                <li><a href="#">Action</a></li>
                <li><a href="#">Another action</a></li>
                <li><a href="#">Something else here</a></li>
                <li role="separator" class="divider"></li>
                <li><a href="#">Separated link</a></li>
                <li role="separator" class="divider"></li>
                <li><a href="#">One more separated link</a></li>
              </ul>
            </li>
          </ul>
    {#        搜索框                #}
          <form class="navbar-form navbar-left">
            <div class="form-group">
              <input type="text" class="form-control" placeholder="Search" oninput="foo()" id="search">
            </div>
            <button type="submit" class="btn btn-default">Submit</button>
              <span id="totalNum"></span>
          </form>
          <ul class="nav navbar-nav navbar-right">
            <li><a href="#">Link</a></li>
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
              <ul class="dropdown-menu">
                <li><a href="#">Action</a></li>
                <li><a href="#">Another action</a></li>
                <li><a href="#">Something else here</a></li>
                <li role="separator" class="divider"></li>
                <li><a href="#">Separated link</a></li>
              </ul>
            </li>
          </ul>
        </div><!-- /.navbar-collapse -->
      </div><!-- /.container-fluid -->
    
        <div class="container">
            <div class="row">
                <div class="col-md-8 col-lg-offset-2">
                    <div id="showData"></div>
                </div>
            </div>
        </div>
    </nav>
    </body>
    
    <script>
        //搜索
        function foo() {
            var searchMsg = $('#search').val();
            console.log(searchMsg);
            $.ajax({
                url:"/app01/index",
                type: "post",
                data: {'search_msg': searchMsg},
                success:function (data) {
                    console.log(data);
                    if (data){
                        //展示结果条数
                        $("#totalNum").html("结果约<b style='color:red'>" + data.hits.total + "<b>")
                        //结果展示
                        var html = '';
                        $.each(data.hits.hits, function (index, item) {
                            //console.log(item._source.title)
                            html += "<a href='+ item.a_url +'>
    " +
                                "                                <div class="article-pic"></div>
    " +
                                "                                <h3>"+item.highlight.title+"</h3>
    " +
                                "                                <div class="article-bar">
    " +
                                "                                    <span class="fn-left"></span>
    " +
                                "                                    <span class="fn-right">
    " +
                                "                                        <em><i class="icon12 icon12-eye"></i></em>
    " +
                                "                                        <em data-class="icon12 icon12-infor" data-articleid="945066"><i class="icon12 icon12-infor"></i>13</em>
    " +
                                "                                    </span>
    " +
                                "                                </div>
    " +
                                "                                <p>"+item._source.summary+"</p>
    " +
                                "                            </a>";
                            $("#showData").html(html)
                        })
                    }
                }
            })
        }
    
    
    </script>
    
    </html>

    7.7 启动项目先访问es路由,后面访问index即可

  • 相关阅读:
    微信小程序在sublime开发代码高亮显示
    CSS之flex兼容
    本地存储(2)
    IE浏览器兼容性问题解决方案
    设计一套方案,解决不同浏览器的兼容问题(2)
    Webpack, 现在最流行的模块打包工具.压缩打包
    Linux环境下安装配置Node.js
    阿里云服务器 linux 怎么安装php(PHPSTUDY)开发环境
    函数与闭包
    内建的控制结构
  • 原文地址:https://www.cnblogs.com/mcc61/p/11512538.html
Copyright © 2020-2023  润新知