一 文档查询操作
1.后续查询主要都是 结构化查询 且 匹配模式为match分词查询
2.对于elasticsearch来说,所有的条件都是可插拔的,彼此之间用','分割
3.所有参数的属性值为列表的,都可以实现多个条件并列存在
1 查询的两种方式
字符串查询 和 结构化查询
是打分机制,反应查询匹配度 分值越高,匹配度越高
查询结果为一条,分数为1.0
查询结果为两条,大概分别为0.5左右
请求方式:GET
请求参数:_search?q=字段:值
查询结果:在返回json的 "hits" 中
GET lqz/_doc/_search?q=from:gu
GET lqz/_doc/_search?q=age:22
请求方式:GET
请求参数:_search
参数值:以json格式 传递
查询结果:在返回json的 "hits" 中
GET lqz/_doc/_search
{
"query": {
"match": {
"from": "gu"
}
}
}
2 DSL的匹配模式
match分词查询 和 term精准查询
match: 会对搜索的关键词进行分词,按分词去搜索
武器很长 ---> 武器 长 有结果
term : 不会对搜索的关键字进行分词,而直接搜索,精准匹配
武器很长 ---> 武器很长 搜不到结果
terms : 多个精准词 and连接
2.1 match分词查询
match :按条件分词匹配
match_all : 查询所有
match_phrase : 短语查询 phrase n. 短语,词组
match_phrase_prefix : 最左前缀查询 匹配的词组以什么开头
GET t1/_doc/_search
{
"query": {
"match_all": {}
}
}
GET t1/_doc/_search slop v.溢出
{
"query": {
"match_phrase": {
"title": {
"query": "中国世界",
"slop": 2
}
}
}
}
默认为0,即没有该参数时,表明query的值 为整体一个词组
GET t1/_doc/_search
{
"query": {
"match_phrase_prefix": {
"desc": "bea"
}
}
}
2.2 term精准查询
term : 精准查询 不会词条分析处理(分词、标点符号删减、分词后的词条全转小写)
terms : 多个精准词 and连接
GET w10/_doc/_search
{
"query": {
"term": {
"t1": "girl"
}
}
}
GET w10/_doc/_search
{
"query": {
"terms": {
"t1": ["beautiful", "sexy"]
}
}
}
不要使用term 对 类型是text的字段 进行查询
因为text类型的字段,会自动分词 且进行标点符号删减 和 全转小写的词条(token)分析处理
3 排序查询
"sort":[
{
"排序字段":{
"order": "desc" 或 "asc"
}
}
]
GET lqz/_doc/_search
{
"query": {
"match": { "from": "gu" }
},
"sort": [
{
"age": {
"order": "desc"
}
}
]
}
GET lqz/_doc/_search
{
"query": {
"match": { "from": "gu" }
},
"sort": [
{
"age": {
"order": "asc"
}
}
]
}
GET lqz/_doc/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"age": {
"order": "asc"
}
}
]
}
4 分页查询
"from" : 从第几条开始
"size" : 返回几条结果
GET lqz/_doc/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"age": {
"order": "desc"
}
}
],
"from": 2,
"size": 2
}
对于elasticsearch来说,所有的条件都是可插拔的,彼此之间用','分割
5 布尔查询
1.多条件的关系查询:与、或、非
2.范围过滤查询:大于、小于 或 什么之间
"bool":{
"关系参数":[
多个查询参数
],
"过滤参数":{
"range": {
"过滤字段": { "属性参数": 值, }
}
}
}
must
should
must_not
filter
gt : >
gte : >=
lt : <
lte : <=
5.1 多条件的关系查询
GET lqz/_doc/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"from": "gu"
}
},
{
"match": {
"name": "顾老二"
}
}
]
}
}
}
GET lqz/_doc/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"from": "gu"
}
},
{
"match": {
"name": "龙套偏房"
}
}
]
}
}
}
GET lqz/_doc/_search
{
"query": {
"bool": {
"must_not": [
{
"match": {
"from": "gu"
}
},
{
"match": {
"tags": "可爱"
}
},
{
"match": {
"age": 18
}
}
]
}
}
}
5.2 范围过滤查询
gt : >
gte : >=
lt : <
lte : <=
GET lqz/_doc/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"from": "gu"
}
}
],
"filter": {
"range": {
"age": {
"lt": 30
}
}
}
}
}
}
GET lqz/_doc/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"from": "gu"
}
}
],
"filter": {
"range": {
"age": {
"gte": 25,
"lte": 30
}
}
}
}
}
}
filter需要在bool内部
如果是and条件,需要用must
如果是should,会认为是should和filter是"或者"的关系
6 查询结果过滤
指的是针对返回的数据,再进行某个字段属性的筛选
eg: 类似于 select name, age from user
"_source":[多个字段属性]
GET lqz/_doc/_search
{
"query": {
"match_all": {
}
},
"_source":["name","age"]
}
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": {}
}
}
GET lqz/_doc/_search
{
"query": {
"match": {
"from": "gu"
}
},
"highlight": {
"pre_tags": "<b class='key' style='color:red'>",
"post_tags": "</b>",
"fields": {
"from": {}
}
}
}
8 聚合函数
sum, avg, max ,min
"aggs": {
"结果字段别名":{
"聚合参数":{
"field": "被聚合的具体字段"
}
}
}
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"]
}
GET lqz/_doc/_search
{
"size": 0,
"query": {
"match_all": {}
},
"aggs": {
"age_group": {
"range": {
"field": "age",
"ranges": [
{
"from": 15,
"to": 20
},
{
"from": 20,
"to": 25
},
{
"from": 25,
"to": 30
}
]
}
},
"aggs": {
"my_avg": {
"avg": {"field": "age"}
}
}
}
}
二 ik分词器使用
1.github下载相应版本
https://github.com/medcl/elasticsearch-analysis-ik/releases
再选择?after=v7.5.2
2.解压到es的plugins目录下
3.重启es
ik_max_word: 会将文本做最细粒度的拆分
eg:会将“中华人民共和国国歌”拆分为
“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”
会穷尽各种可能的组合,适合 Term 精准查询
ik_smart: 会做最粗粒度的拆分
eg:会将“中华人民共和国国歌”拆分为“中华人民共和国, 国歌”,适合 match_Phrase 短语查询
ik分词配置文件:ik文件/config目录
-IKAnalyzer.cfg.xml
-main.dic
-surname.dic
-suffix.dic
-preposition.dic
-stopword.dic
-quantifier.dic
GET _analyze
{
"analyzer": "ik_max_word",
"text": "白雪公主和十个小矮人"
}
PUT books
{
"mappings": {
"properties":{
"title":{
"type":"text",
"analyzer": "ik_max_word"
},
"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 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": "十"
}
}
}
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 原生集成
Official low-level client for Elasticsearch
import requests
res=requests.put("http://localhost:9200/lqz5")
print(res)
pip3 install elasticsearch
from elasticsearch import Elasticsearch
obj = Elasticsearch("http://localhost:9200")
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包裹会报错
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': {}}}
query = {'query': {'match': {'title': '十个'}}}
query = {'query': {'range': {'age': {'gt': 11}}}}
allDoc = obj.search(index='books', doc_type='_doc', body=query)
print(allDoc['hits']['hits'][0]['_source'])
2 DSL集成
Elasticsearch DSL is a high-level
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
connections.create_connection(hosts=["localhost"])
class Article(Document):
title = Text(analyzer='ik_max_word')
author = Text()
class Index:
name = 'myindex'
def save(self, **kwargs):
return super(Article, self).save(**kwargs)
if __name__ == '__main__':
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()
s = s.filter('match', title="测试")
results = s.execute()
print(results[0])
results[0].title="李清照阿斯顿发送到发送阿斯蒂"
results[0].save()
四 集群搭建及脑裂问题
只要ES节点能ping通,就自动加入到集群节点中
配置各节点的配置文件:各自ES下的 "\config\elasticsearch.yml"文件
集群名称是my_es1
集群端口是9300
节点名称是node1
监听本地IP和9200端口
可以有权限成为主节点和读写磁盘
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"]
集群名称是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"]
集群名称是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"]
集群名称是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个节点一组
discovery.zen.minimum_master_nodes: 3
PUT /_cluster/settings
{
"persistent":{
"discovery.zen.minimum_master_nodes":2
}
}
当2个节点失去与主节点通信后,因节点数量 小于 能够选取主节点的候补节点 最小数量 3,就无法选取新的主节点
五 打分机制
确定文档 和 查询匹配度(查询结果和查询参数有多么相关) 的过程 被称为打分
1.TF 词频 term frequency
一个词条 在某个文档中 出现的次数
2.IDF 逆文档频率 inverse document frequency
一个词条 在索引中,多少个的不同文档中出现过
六 如何将mysql的数据同步ES
mysql中一个库有多个表,怎么同步到ES中
1.并不是mysql所有的数据表,都需要同步到ES中
2.只是利用ES的倒排索引来做全文检索,只需要全文检索的字段数据
1.将需要用来全文检索的数据,从mysql中查询出来
2.将需要同步的数据,拼凑成ES的json格式
3.若在ES中全文检索后,查到了某条数据(但并不详细),此时,再根据数据的主键,去mysql详细查询
1.mysql中查出 作者name、文章id、文章title、文章content 等多个表的数据
2.自定义处理拼成一个文档json数据
3.同步插入到ES中
前端在ES中查出'你好'后
若前端需要的数据 如文章id、文章内容 ES中有 就直接返回给前端
若前端需要的数据 如文章价格、文章类型等其他字段 ES中没有 再根据文章id或其他主键 去mysql查询
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构