ES03--文档详细查询、IK分词器、python集成ES、集群搭建、打分机制

一 文档查询操作

# 强调:
  1.后续查询主要都是 结构化查询 且 匹配模式为match分词查询

  2.对于elasticsearch来说,所有的条件都是可插拔的,彼此之间用','分割  
   
  3.所有参数的属性值为列表的,都可以实现多个条件并列存在 

1 查询的两种方式

# Elasticsearch之查询的两种方式
  字符串查询 和 结构化查询

    
# 文档的查询结果 有项参数 max_score 最大分数
  是打分机制,反应查询匹配度  分值越高,匹配度越高
  # eg: 
    查询结果为一条,分数为1.0
    查询结果为两条,大概分别为0.5左右
    
    
# 1.查询字符串 (query string)   # 不常用
    请求方式:GET
    请求参数:_search?q=字段:值  # 类似:参数在请求路径url中
    
    查询结果:在返回json的 "hits"# eg:
  # 查询from字段是gu的所有人
  GET lqz/_doc/_search?q=from:gu
    
  # 查询age是22的人
  GET lqz/_doc/_search?q=age:22

      
# 2.结构化查询 (DSL)   # 常用  
    请求方式:GET
    请求参数:_search
    参数值:以json格式 传递   # 类似:参数在请求体中
    
    查询结果:在返回json的 "hits"# eg:
  # 查询from字段是gu的所有人
  GET lqz/_doc/_search
  {
    "query": {
      "match": {       # 匹配模式
        "from": "gu"   # 字段: 查询值
      }
    }
  }

2 DSL的匹配模式

# 结构化查询的匹配模式:
  match分词查询 和 term精准查询   
    
    
# match、term和terms的区别   # 面试常问
  match: 会对搜索的关键词进行分词,按分词去搜索   # 常用
    # eg:  存数据的时候,用了分词  [确实 很 黄,武器 很 长,性格 很 直]
     武器很长 ---> 武器  长  有结果
     
  term : 不会对搜索的关键字进行分词,而直接搜索,精准匹配
    # eg: 
     武器很长 ---> 武器很长   搜不到结果
    
  terms : 多个精准词  and连接
    
    
    
# 下面的查询:都是基于 结构化查询的 match匹配模式

2.1 match分词查询

# match系列  常用
  match               :按条件分词匹配
  match_all           : 查询所有
  match_phrase        : 短语查询       phrase  n. 短语,词组
  match_phrase_prefix : 最左前缀查询   匹配的词组以什么开头

    
# eg:
  # 查询所有
  GET t1/_doc/_search
  {
    "query": {
      "match_all": {}  # 值为空,表示没有查询条件
    }
  }


  # 短语/词组查询
  GET t1/_doc/_search    slop v.溢出
  {
    "query": {
      "match_phrase": {
        "title": {
          "query": "中国世界",
          "slop": 2  # 中国和世界之间最多间隔2个字符
        }
      }
    }
  }
  
  # slop: 表明该查询的词组 分组后 中间最多有多少个字符间隔  
          默认为0,即没有该参数时,表明query的值 为整体一个词组
    
    
  # 最左前缀查询   还有一个max_expanions参数搭配使用  具体再看
  GET t1/_doc/_search
  {
    "query": {
      "match_phrase_prefix": {
        "desc": "bea"  
      }
    }
  }

2.2 term精准查询

# term 系列  不常用
  term  : 精准查询  不会词条分析处理(分词、标点符号删减、分词后的词条全转小写)
        
  terms : 多个精准词  and连接
        
        
# eg: 
  # term 
  GET w10/_doc/_search
  {
     "query": {
      "term": {
         "t1": "girl"
       }
     }
   }
        
  # terms
  GET w10/_doc/_search
  {
    "query": {
      "terms": {
        "t1": ["beautiful", "sexy"]
      }
    }
  }
    
    
# 注:
  不要使用term 对 类型是text的字段 进行查询
  因为text类型的字段,会自动分词  且进行标点符号删减 和 全转小写的词条(token)分析处理

3 排序查询

# 不是所有字段都支持排序,只支持数字类型 和时间类型,字符串不支持
   
# 排序参数:  # sort对应列表中,可以加多个排序字段,以','分割
  "sort":[   
    {
      "排序字段":{
        "order": "desc""asc"  # 降 升
      }   
    }
  ]
	

# eg: 降序  desc
GET lqz/_doc/_search
{
  "query": {
    "match": { "from": "gu" }
  },
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ]
}


# eg: 升序  asc
GET lqz/_doc/_search
{
  "query": {
    "match": { "from": "gu" }
  },
  "sort": [
    {
      "age": {
        "order": "asc"
      }
    }
  ]
}

# eg: 升序  查所有 且以age升序
GET lqz/_doc/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "age": {
        "order": "asc"
      }
    }
  ]
}

4 分页查询

# 分页参数:
  "from" : 从第几条开始
  "size" : 返回几条结果

    
# eg: 查询结果从第二条开始,取两条
GET lqz/_doc/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ], 
  "from": 2,
  "size": 2
}


# 注意:
  对于elasticsearch来说,所有的条件都是可插拔的,彼此之间用','分割  
    # eg: 上述分页查询,可以将排序参数直接去掉

5 布尔查询

# 布尔查询:即多个条件的组合查询 ,或称为 子查询
 
# 布尔查询的主要功能:
  1.多条件的关系查询:与、或、非
    
  2.范围过滤查询:大于、小于 或 什么之间 
  

# 布尔参数:
  "bool":{
    "关系参数":[
        多个查询参数   # 不能直接在match中加多个条件
    ],
      
     "过滤参数":{
        "range": {
          "过滤字段": { "属性参数": 值, }  # 属性参数可多个  eg: 大于什么,且小于什么
        }
      }
  }
  
  # 关系参数:
    must     # and 与  
    should   # or  或
    must_not # not 非 

    
  # 过滤参数:
    filter
    
    # 属性参数:
      gt   :  >
      gte  :  >=
      lt   :  <
      lte  :  <=

5.1 多条件的关系查询

# eg: must and条件  并且
GET lqz/_doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "from": "gu"
          }
        },
        {
          "match": {
            "name": "顾老二"
          }
        }
      ]
    }
  }
}

# eg:should or条件  或者
GET lqz/_doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "from": "gu"
          }
        },
        {
          "match": {
            "name": "龙套偏房"
          }
        }
      ]
    }
  }
}


# eg: must_not not条件   都不是
GET lqz/_doc/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "match": {
            "from": "gu"
          }
        },
        {
          "match": {
            "tags": "可爱"
          }
        },
        {
          "match": {
            "age": 18
          }
        }
      ]
    }
  }
}

5.2 范围过滤查询

# filter过滤条件: 大于、小于 或 什么之间 
   gt   :  >
   gte  :  >=
   lt   :  <
   lte  :  <=

    
# 过滤查询:字段from是gu,且 age<30 
GET lqz/_doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "from": "gu"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "lt": 30
          }
        }
      }
    }
  }
}


# 范围查询:字段from是gu,且25<= age <=30
GET lqz/_doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "from": "gu"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "gte": 25,
            "lte": 30
          }
        }
      }
    }
  }
}


# 注意:
  filter需要在bool内部
    如果是and条件,需要用must   # 建议使用must, should会比较乱
    如果是should,会认为是should和filter"或者"的关系

6 查询结果过滤

# 查询结果过滤:
  指的是针对返回的数据,再进行某个字段属性的筛选 
    eg: 类似于 select name, age from user  

        
# 结果过滤参数:
  "_source":[多个字段属性]
        
   # 注意:"_source" 和 "query" 是平级的
        
    
# eg: 基本使用
GET lqz/_doc/_search
{
  "query": {
    "match_all": {
      }
  },
  "_source":["name","age"]
}


# eg:就相当于 mysql中 跟了一堆where之后,前面select再某些字段
GET lqz/_doc/_search
{
  "query": {
    "bool": {
      "must":{
        "match":{"from":"gu"}
      },
      
      "filter": {
        "range": {
          "age": {
            "lte": 25
          }
        }
      }
    }
  },
  "_source":["name","age"]
}

7 高亮查询

# 高亮查询:
  指的是针对返回的结果,将某些字段属性 增加颜色样式 进行突出显示

    
# 高亮参数:
  "highlight": {
    # 自定义高亮样式   可不加这两个,有默认高亮样式   注意单引号
    "pre_tags": "<b class='key' style='color:red'>",  # 在高亮字段前 加标签
    "post_tags": "</b>",  # 在高亮字段后 加标签
    
    # 需要高亮的字段
    "fields": {  
      "from": {}
    }
  }
    
  # 注意:"highlight" 与 "query” 同级
    
    
# eg:
GET lqz/_doc/_search
{
  "query": {
    "match": {
      "from": "gu"
    }
  },
    
  "highlight": {
    "pre_tags": "<b class='key' style='color:red'>",
    "post_tags": "</b>",
    "fields": {
      "from": {}
    }
  }
}

8 聚合函数

# 聚合函数:    尽量少ES中使用,因为ES主要是用来做全文检索,使用聚合会影响效率
  sum, avg, max ,min

# 聚合或分组参数:  注意:"aggs" 与 "query” 同级

  "aggs": {
    "结果字段别名":{
      "聚合参数":{
        "field": "被聚合的具体字段"
      }
    }    
  }

    
# eg: 类似mysql的 select avg(age) as my_avg from 表 where from=gu;
GET lqz/_doc/_search
{
  "query": {
    "match": {
      "from": "gu"
    }
  },
  "aggs": {
    "my_avg": {
      "avg": {
        "field": "age"
      }
    }
  },
  "_source": ["name", "age"]
}


# 最大年龄
GET lqz/_doc/_search
{
  "query": {
    "match": {
      "from": "gu"
    }
  },
  "aggs": {
    "my_max": {
      "max": {
        "field": "age"
      }
    }
  },
  "_source": ["name", "age"]
}


# 最小年龄
GET lqz/_doc/_search
{
  "query": {
    "match": {
      "from": "gu"
    }
  },
  "aggs": {
    "my_min": {
      "min": {
        "field": "age"
      }
    }
  },
  "_source": ["name", "age"]
}

# 总年龄
GET lqz/_doc/_search
{
  "query": {
    "match": {
      "from": "gu"
    }
  },
  "aggs": {
    "my_sum": {
      "sum": {
        "field": "age"
      }
    }
  },
  "_source": ["name", "age"]
}



# 分组查询   因ES每个索引,只有一个文档  不存在多表分组的情况

# 查询所有人的年龄段,并且按照`15~20,20~25,25~30`分组,并且算出每组的平均年龄
GET lqz/_doc/_search
{
  "size": 0,   # 查询结果返回0条   意思是query查出的数据不显示
  "query": {
    "match_all": {}
  },
  "aggs": {
    "age_group": {        # 结果字段别名
      "range": {          # 以范围分组
        "field": "age",   # 分组的字段
        "ranges": [       # 每个组的范围
          {
            "from": 15,
            "to": 20
          },
          {
            "from": 20,
            "to": 25
          },
          {
            "from": 25,
            "to": 30
          }
        ]
      }
    },
    "aggs": {       # 再对分组后的结果,进行聚合函数计算  这个aggs需要和分组age_group 同级
      "my_avg": {
        "avg": {"field": "age"}
      }
    }
  }
}

二 ik分词器使用

# IK分词器的下载安装
  1.github下载相应版本
    https://github.com/medcl/elasticsearch-analysis-ik/releases 
    再选择?after=v7.5.2
  2.解压到es的plugins目录下
  3.重启es


# ik_max_word 和 ik_smart 什么区别?

  ik_max_word: 会将文本做最细粒度的拆分 
    eg:会将“中华人民共和国国歌”拆分为
       “中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”
        会穷尽各种可能的组合,适合 Term 精准查询

  ik_smart: 会做最粗粒度的拆分
    eg:会将“中华人民共和国国歌”拆分为“中华人民共和国, 国歌”,适合 match_Phrase 短语查询
 
  # 一般:文章标题 用 ik_max_word  文章内容 用 ik_smart 

    

# 若ik分词器,分词效果不太贴切  可修改分词词库
  ik分词配置文件:ik文件/config目录   # 自己添加词 或配置
    
    -IKAnalyzer.cfg.xml # 用来配置自定义的词库
    -main.dic           # ik原生内置的中文词库,大约有27万多条,只要是这些单词,都会被分在一起
    -surname.dic        # 中国的姓氏
    -suffix.dic         # 特殊(后缀)名词   例如`乡、江、所、省`等
    -preposition.dic    # 中文介词          例如`不、也、了、仍`等
    -stopword.dic       # 英文停用词库      例如`a、an、and、the`等
    -quantifier.dic     # 单位名词          例如`厘米、件、倍、像素`等
    
    
# eg: 简单使用--查看分词器,会对文本分词有哪些结果
GET _analyze
{
  "analyzer": "ik_max_word",
  "text": "白雪公主和十个小矮人"
}


##### eg: 'ik_max_word'分词
# 准备数据--创建索引
PUT books
{
  "mappings": {
    "properties":{
      "title":{
        "type":"text",
        "analyzer": "ik_max_word"   # 指定哪种分词器分词
      },
      "price":{
        "type":"integer"   # 未指定分词器  采用默认standard分析器
      },
      "addr":{
        "type":"keyword"
      },
      "company":{
        "properties":{
          "name":{"type":"text"},
          "company_addr":{"type":"text"},
          "employee_count":{"type":"integer"}
        }
      },
      "publish_date":{"type":"date","format":"yyy-MM-dd"}
    }
  }
}

# 准备数据--插入文档
PUT books/_doc/1
{
  "title":"大头儿子小偷爸爸",
  "price":100,  
  "addr":"北京天安门",
  "company":{
    "name":"我爱北京天安门",
    "company_addr":"我的家在东北松花江傻姑娘",
    "employee_count":10
  },
  "publish_date":"2019-08-19"
}

PUT books/_doc/2
{
  "title":"白雪公主和十个小矮人",
  "price":"99",
  "addr":"黑暗森里",
  "company":{
    "name":"我的家乡在上海",
    "company_addr":"朋友一生一起走",
    "employee_count":10
  },
  "publish_date":"2018-05-19"
}

# 查看索引映射
GET books/_mapping


# 查询文档
GET books/_search
{
  "query": {
    "match": {
      "title": "十"
    }
  }
}


##### eg: 'ik_smart'分词
# 准备数据--创建索引
PUT books2
{
  "mappings": {
    "properties":{
      "title":{
        "type":"text",
        "analyzer": "ik_smart"   # 指定哪种分词器分词
      },
      "price":{
        "type":"integer"
      },
      "addr":{
        "type":"keyword"
      },
      "company":{
        "properties":{
          "name":{"type":"text"},
          "company_addr":{"type":"text"},
          "employee_count":{"type":"integer"}
        }
      },
      "publish_date":{"type":"date","format":"yyy-MM-dd"}
    }
  }
}

# 准备数据--插入文档
PUT books2/_doc/1
{
  "title":"大头儿子小偷爸爸",
  "price":100,  
  "addr":"北京天安门",
  "company":{
    "name":"我爱北京天安门",
    "company_addr":"我的家在东北松花江傻姑娘",
    "employee_count":10
  },
  "publish_date":"2019-08-19"
}

PUT books2/_doc/2
{
  "title":"白雪公主和十个小矮人",
  "price":"99",
  "addr":"黑暗森里",
  "company":{
    "name":"我的家乡在上海",
    "company_addr":"朋友一生一起走",
    "employee_count":10
  },
  "publish_date":"2018-05-19"
}

# 查询文档
GET books2/_search
{
  "query": {
    "match": {
      "title": "十个"
    }
  }
}

三 Python中集成ES

1 原生集成

# 原生集成  等同于pymysql  原生操作
  Official low-level client for Elasticsearch
  
  # 因为ES是遵守restful规范的Http请求方式,故也可以直接用request模块直接发http请求
    import requests
    res=requests.put("http://localhost:9200/lqz5")
    print(res)

    
# 安装 elasticsearch   
  pip3 install elasticsearch


from elasticsearch import Elasticsearch

# 连接Elasticsearch
obj = Elasticsearch("http://localhost:9200")   # 默认连接本地elasticsearch

# 创建索引(Index)  并插入数据
result = obj.indices.create(index='user', body={"userid":'1','username':'lqz'},ignore=400)
print(result)
# 删除索引
result = obj.indices.delete(index='user', ignore=[400, 404])


# 插入文档数据
data = {'userid': '1', 'username': 'lqz','password':'123'}
result = obj.create(index='news', doc_type='_doc', id=1, body=data)
print(result)
    
# 更新文档数据    doc包裹是局部更新
  '''
  注:不用doc包裹会报错
  ActionRequestValidationException[Validation Failed: 1: script or doc is missing
  '''
data ={'doc':{'userid': '1', 'username': 'lqz','password':'123ee','test':'test'}}
result = obj.update(index='news', doc_type='_doc', body=data, id=1)
print(result)

# 删除文档数据
result = obj.delete(index='news', doc_type='_doc', id=1)
print(result)


# 查询文档数据
# 查找所有文档
query = {'query': {'match_all': {}}}

# 查找名字叫做jack的所有文档
query = {'query': {'match': {'title': '十个'}}}

# 查找年龄大于11的所有文档
query = {'query': {'range': {'age': {'gt': 11}}}}

allDoc = obj.search(index='books', doc_type='_doc', body=query)

# print(allDoc)
print(allDoc['hits']['hits'][0]['_source'])

2 DSL集成

# 原生集成  等同于ORM
  Elasticsearch DSL is a high-level

# 安装 elasticsearch   
  pip3 install elasticsearch-dsl


from datetime import datetime

# 导入一堆类 包含映射类型、分词器等
from elasticsearch_dsl import Document, Date, Nested, Boolean, \
analyzer, InnerDoc, Completion, Keyword, Text,Integer

from elasticsearch_dsl.connections import connections


# 创建ES连接对象
connections.create_connection(hosts=["localhost"])


# 类似于orm的表模型  
class Article(Document):
    title = Text(analyzer='ik_max_word')
    author = Text()
    
    # 指定表 所属的索引内容  eg:索引名
    class Index:
        name = 'myindex'
    
    # 自定义save方法   可用于在保存数据之前,额外添加其他操作
    def save(self, **kwargs):
        # 调用父类的save方法
        return super(Article, self).save(**kwargs)


if __name__ == '__main__':
    # 调用类的init方法   创建索引
    Article.init()    
    
    # 新增数据
    article = Article()
    article.title = "测试测试阿斯顿发送到发斯蒂芬啊啊士大夫阿斯蒂芬"
    article.author = "lqz"
    article.save()  # 数据就保存了

    # 查询数据
    s = Article.search()
    s = s.filter('match', title="测试")
   
    results = s.execute()  # 执行  返回是列表  里面是数据对象
    print(results[0].title)

    # 删除数据
    s = Article.search()
    s = s.filter('match', title="李清照").delete()

    # 修改数据
    s = Article().search()    # 试试 Article 不加括号
    s = s.filter('match', title="测试")
    results = s.execute()
    print(results[0])
    
    results[0].title="李清照阿斯顿发送到发送阿斯蒂"
    results[0].save()

四 集群搭建及脑裂问题

# ES使用两种不同的方式来发现对方:
  # 1.广播方式: 在同一个网络中,只要开启多个es实例   一般不用  方便,但过程不可控
      只要ES节点能ping通,就自动加入到集群节点中
    
  # 2.单播方式: 指定跟谁谁谁组成集群    unicast  n. 单一传播


# eg:4台机器的集群(单播方式)
      配置各节点的配置文件:各自ES下的 "\config\elasticsearch.yml"文件

# elasticsearch 1节点
  集群名称是my_es1
  集群端口是9300    # 集群中 节点相互交互识别的端口 transport.tcp.port
  节点名称是node1
  监听本地IP和9200端口
  可以有权限成为主节点和读写磁盘  
    # 默认:可成为主节点 和 可进行读写存储 
    # node.data:false  只能读  不能写

cluster.name: my_es1
node.name: node1
network.host: 127.0.0.1
http.port: 9200
transport.tcp.port: 9300
discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300", "127.0.0.1:9302", "127.0.0.1:9303", "127.0.0.1:9304"]

    
# elasticsearch 2节点
  集群名称是my_es1
  集群端口是9302
  节点名称是node2
  监听本地IP和9202端口
  可以有权限成为主节点和读写磁盘

cluster.name: my_es1
node.name: node2
network.host: 127.0.0.1
http.port: 9202
transport.tcp.port: 9302
node.master: true
node.data: true
discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300", "127.0.0.1:9302", "127.0.0.1:9303", "127.0.0.1:9304"]

    
# elasticsearch 3节点
  集群名称是my_es1
  集群端口是9303
  节点名称是node3
  监听本地IP和9203端口
  可以有权限成为主节点和读写磁盘

cluster.name: my_es1
node.name: node3
network.host: 127.0.0.1
http.port: 9203
transport.tcp.port: 9303
discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300", "127.0.0.1:9302", "127.0.0.1:9303", "127.0.0.1:9304"]

    
# elasticsearch4节点
  集群名称是my_es1
  集群端口是9304
  节点名称是node4
  监听本地IP和9204端口
  仅能读写磁盘而不能被选举为主节点    

cluster.name: my_es1
node.name: node4
network.host: 127.0.0.1
http.port: 9204
transport.tcp.port: 9304
node.master: false
node.data: true
discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300", "127.0.0.1:9302", "127.0.0.1:9303", "127.0.0.1:9304"]

    
# 由上例的配置可以看到:
  各节点有一个共同的集群名字my_es1,但由于是本地环境,所以各节点的名字不能一致
  分别启动它们,它们通过单播列表相互介绍,发现彼此,然后组成一个my_es1集群。
  谁是老大则是要看谁先启动了!



# 脑裂问题:
    假设有5个节点,由于网络问题,部分节点失去与主节点的通信
    然后部分节点就开始选举新的主节点,继续处理请求
    会形成了两个集群 
    eg:2个节点一组,3个节点一组

# 防止脑裂:设置集群主节点的候补节点的 最小数量:(集群节点总数/2 +1的个数)
  discovery.zen.minimum_master_nodes: 3   # 3=5/2 +1
        
  # 除了在配置文件设置,也可以动态设置
  PUT /_cluster/settings
  {
     "persistent":{
        "discovery.zen.minimum_master_nodes":2
     }
  }
        
  # 解决原理:2个节点失去与主节点通信后,因节点数量 小于 能够选取主节点的候补节点 最小数量 3,就无法选取新的主节点

五 打分机制

# 打分
  确定文档 和 查询匹配度(查询结果和查询参数有多么相关) 的过程 被称为打分

# 打分的运作机制:TF-IDF
  1.TF  词频 term frequency
    一个词条 在某个文档中 出现的次数  
      # 出现的次数越多  表示相关度越高   分数应该更高
    
  2.IDF 逆文档频率 inverse document frequency
    一个词条 在索引中,多少个的不同文档中出现过
      # 出现的数量越多  表示该词越不关键  分数应该更低
        
  # 总结:词频越高、逆文档频率越低  --->  打分越高

六 如何将mysql的数据同步ES

# 思考:
  mysql中一个库有多个表,怎么同步到ES中  # ES7.0之后,每个索引库只含有一个文档('_doc')

# 注意:
  1.并不是mysql所有的数据表,都需要同步到ES中
  2.只是利用ES的倒排索引来做全文检索,只需要全文检索的字段数据
   

# 操作步骤:
  1.将需要用来全文检索的数据,从mysql中查询出来 
  2.将需要同步的数据,拼凑成ES的json格式  # 各字段存放在同一个文档即可
  3.若在ES中全文检索后,查到了某条数据(但并不详细),此时,再根据数据的主键,去mysql详细查询
    
  # 意义:ES并不是用来代替mysql来数据查询,而只是作为全文检索,来加快整体的数据查询


# eg: 查出'文章标题' 或 '文章内容' 或 '作者' 或 '出版社' 中 有关键字 '你好' 的文章
  1.mysql中查出 作者name、文章id、文章title、文章content 等多个表的数据
  2.自定义处理拼成一个文档json数据
  3.同步插入到ES中
    
  # 后续过程:
    前端在ES中查出'你好'后
    若前端需要的数据  如文章id、文章内容           ES中有   就直接返回给前端
    若前端需要的数据  如文章价格、文章类型等其他字段  ES中没有 再根据文章id或其他主键  去mysql查询   # 这也是回表查询 
posted @   Edmond辉仔  阅读(155)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示