最近在python项目中操作es,有些问题需要记录一下:
1,一般会使用elastic Kibana 使用命令去操作es,但是es不像mysql那样,可以快速导入导出,做数据恢复,如果把某个index删掉了,或者弄坏了,那么需要很长的恢复时间,甚至恢复不了,所以使用命令行的时候要格外小心,我通过下面的几个步骤来尽量规避风险:
a,命令执行前,再次检查链接的环境
b,在生产环境,执行任何命令前,都应该在测试环境先执行一遍,检查该,命令是否满足了语义。POST/DELETE 都可能改写index,在执行前都要去测试环境提前执行一遍。
特别是DELETE语句,有的时候,我们可能想立刻删除掉线上的某条数据(在页面没有删除按钮),如果漏了后面的id,将会删除整个index,最好先在测试环境,找到对应的index去操作一遍,最后再select count(*) from index 下,看看是否真的只删掉了这一条。
# 步骤一:现在测试环境执行查询语句
POST test_index_dev/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "laibincs"
}
}
]
}
}
}
# 步骤二:正确的按照id删除
DELETE test_index_dev/_doc/jsjhdgxhhhd90998
# 步骤三:再次执行步骤一,检查数据是否存在
# 步骤四:检查总数是否只减少了1
# 步骤五:都正确的情况下,再去操作生产环境
不要觉得麻烦,一定要严格遵守。
2,建议在python中使用elasticsearch_dsl来链接es,有通用的模式:
from elasticsearch_dsl import Q
from elasticsearch_dsl import Text, Document, Date, Keyword
from elasticsearch_dsl.connections import connections
elasticsearch = connections.create_connection(hosts=conf.ELASTICSEARCH_HOSTS,
http_auth=(conf.ELASTICSEARCH_USERNAME, conf.ELASTICSEARCH_PASSWORD))
class UserDocument(Document):
user_name = Keyword()
user_age = Keyword()
user_context = Text(analyzer="ik_max_word", search_analyzer="ik_smart")
create_time = Date()
class Index:
name = "es_user_index"
class EsUserDao:
userDocument = None
def __init__(self):
self.userDocument = UserDocument()
def search(self):
return self.userDocument.search()
def save_one(self, user_document):
# refresh 变量控制新保存的数据,是否立刻刷新,保证下次查询立刻可见
user_document.save(refresh=True)
def delete_by_doc_ids(self, doc_ids):
self.search() \
.filter("ids", values=doc_ids) \
.delete()
def find_one_by_doc_id(self, doc_id):
return self.userDocument.get(id=doc_id)
# highlight_fields = ["name","user_context"]
def find_by_condition(self, request):
search = self.search()
# 准确查询
if request.name is not None:
search = search.query("bool", must=[Q("term", name=request.name)])
# 关键词高亮查询
if request.keyword is not None:
search = search.query("multi_match", query=request.keyword, fields=request.highlight_fields)
search = search.highlight(*tuple(request.highlight_fields), fragment_size=50)
if request.age is not None:
search = search.query("bool", must=[Q("term", age=request.age)])
# 范围查询
if request.create_time is not None:
search = search.query('range', create_time={'gte': request.min_time, 'lte': request.max_time})
# 分页与排序
rp = search \
.source(["name", "age"]) \
.extra(from_=request.from_index, size=request.page_size) \
.sort({"create_time": {"order": "desc"}}) \
.execute()
return rp
# 根据id更新 update_content = {"name": "change_new_name"}
def update_by_id(self, report_id, update_content):
elasticsearch.update(index=conf.REPORT_INDEX, id=report_id, body={"doc": update_content})
if __name__ == '__main__':
UserDocument.init()
a, 创建一个链接
b,python中的class需要继承自Document
c,在内部定义一个Index类,name指明对应es的index。
d,建立一个新的Dao类来提供增删改的接口
需要注意高亮显示那里,有的时候,我们的查询条件可能是 name ="laibin" and keyword ="laibin"
假如数据库中,有一个doc满足 user_context 中含有"laibin"且 name =''laibincs'的情况下,es也会把name当作高亮显示,但这是不对的,需要做判断
3,缺少python对es去重或者分组查询的。后续补上。。。。