翼度科技»论坛 编程开发 python 查看内容

Python elasticsearch 使用心得

10

主题

10

帖子

30

积分

新手上路

Rank: 1

积分
30
一、配置
  1. python == 3.6/3.8
  2. # 更高版本的elasticsearch会出现doc_type被统一成_doc导致旧版语句报错的情况
  3. pip install elasticsearch==7.8.0
复制代码
二、连接es
  1. from elasticsearch import Elasticsearch
  2. es = Elasticsearch('ip:port')
复制代码
三、查看索引是否存在,删除索引
  1. # 浏览器查看索引
  2. # ip:路由地址;port:运行端口(默认9200);index_name:要查看
  3. # 查看所有索引
  4. http://ip:port/_cat/indices?v&pretty
  5. # 查看单个索引
  6. http://ip:port/index_name/_settings?pretty
  7. # python查看elasticsearch是否存在
  8. # es.indices.exists(index="index_name")
  9. # 删除索引
  10. # es.indices.delete(index='index_name', ignore=[400, 404])
复制代码
三、创建索引与映射
  1. # 索引参数设置
  2. # 索引的静态参数一旦被设置,不能改变;动态参数可以改变
  3. def create_index(es, index_name):
  4.     settings = {
  5.         'settings':
  6.             {
  7.                 "number_of_shards": 5,  # 设置主索引的主分片数,静态参数
  8.                 "number_of_replicas": 0,  # 设置主索引的副本数,动态参数
  9.                 "max_result_window": 10000000,  # 设置一次检索最大返回数量
  10.                 "track_total_hits": True,  # 使最大返回设置生效的参数
  11.             }
  12.     }
  13.     if es.indices.exists(index_name):
  14.         print(u"%s 已存在" % index_name)
  15.     else:
  16.         es.indices.create(index=index_name, body=settings)
  17.         print(index_name + "索引创建成功")
  18. res = es.indices.create(index='index_name', ignore=400)
  19. print(res)
  20. # 创建映射(索引内每一个字段的设置)
  21. """
  22. 分词器主要有两种情况会被使用:
  23. 第一种是插入文档时,将text类型的字段做分词然后插入倒排索引,对应analyzer
  24. 第二种就是在查询时,先对要查询的text类型的输入做分词,再去倒排索引搜索,对应search_analyzer
  25. 如果想要让 索引 和 查询 时使用不同的分词器,ElasticSearch也是能支持的,只需要在字段上加上search_analyzer参数
  26. 在索引时,只会去看字段有没有定义analyzer,有定义的话就用定义的,没定义就用ES预设的
  27. 在查询时,会先去看字段有没有定义search_analyzer,如果没有定义,就去看有没有analyzer,再没有定义,才会去使用ES预设的
  28. """
  29. mapping = {
  30.     'properties': {
  31.         # 简单设置
  32.         'title': {
  33.             'type': 'string',
  34.             'analyzer': 'jieba',
  35.         },
  36.         # 较复杂的设置
  37.         'content': {
  38.             'include_in_all': True,  # 控制_all查询时是否需要查询该字段,默认True,若是false将不会被_all查询
  39.             'analyzer': 'jieba',  # 查询和索引统一的分词器
  40.             # 'searchAnalyzer': 'jieba',  # 单独设置查询分词器
  41.             'index': "analyzed",  # 控制字段怎样建索引或查询。no不能被查询;not_analyzed只存储原始值,不分词;analyzed分词存储
  42.             'boost': 2,  # 控制该字段的查询权重,大于1会增加相对权重
  43.             'term_vector': 'with_positions_offsets',  # 存储完整的term vector信息,包括field terms、position、offset
  44.             'type': 'string',  # 旧版支持。从ElasticSearch 5.x开始不再支持string,由text和keyword类型替代。
  45.         },
  46.     }
  47. }
  48. # 设置mapping信息:可以指定字段的类型、是否进行分词、默认值、是否被索引
  49. # 分词器analyzer和搜索分词器search_analyzer。ik_max_word为默认的英文分词器,jieba等其他分词器需要额外安装。
  50. result = es.indices.put_mapping(index='index_name', doc_type='doc', body=mapping)
  51. print(result)
复制代码
四、查询索引

1、match_all查询所有
  1. body = {
  2.         "query": {
  3.             "match_all": {},
  4.         },
  5.         "size": 50,  # size不设置会默认返回5条
  6.     }
  7. result = es.search(index='index_name', doc_type='doc_type', body=body)
复制代码
2、分词相关查询

关键词keyword类型text类型是否支持分词term完全匹配查询条件中关键词不会被分词,它必须整个关键词和document中的某个分词匹配,才能搜索到,多个分词时必须连续,顺序不能颠倒。是match完全匹配match分词结果和text的分词结果有相同的即可否match_phrase完全匹配match_phrase的分词结果必须在text字段分词中都包含,而且顺序必须相同,而且必须都是连续的。是query_string完全匹配query_string中和match_string基本一样,区别是它不考虑顺序是
  1. # term是代表完全匹配,即不进行分词器分析,文档中必须包含整个搜索的词汇
  2. body = {
  3.   "query": {
  4.     "term": {
  5.       "content": "汽车保养"
  6.     "from": 1,  # 从第几个开始返回
  7.     "size": 30,  # 一次返回多少个
  8.     }
  9.   }
  10. }
  11. # match 分词,部分匹配查询,包含文本分词后的一个或多个词即符合条件
  12. body = {
  13.     "query": {
  14.         "match": {"title": "宝马法拉利兰博基尼"},
  15.     },
  16. }
  17. # match_phrase  分词,完全匹配查询,包含文本分词后的所有词才符合条件,且匹配词的顺序必须完全按照分词前的顺序
  18. # 例如分词后为宝马、法拉利、兰博基尼,匹配顺序宝马必须在法拉利之前,法拉利必须在兰博基尼之前
  19. body = {
  20.     "query": {
  21.         "match_phrase": {"title": "宝马法拉利兰博基尼"},
  22.     },
  23. }
  24. # query_string,分词,不考虑顺序
  25. body = {
  26.     "query": {
  27.         "query_string": {
  28.             "fields": ["title", "content"],
  29.             "query": text,
  30.         }
  31.     }
  32. }
复制代码
3、bool组合查询
  1. """
  2. bool能将多个简单查询组合起来。
  3. 使用 must、should、must_not、filter 选项来表示简单查询之间的逻辑,每个选项都可以出现 0 次到多次。
  4. must:文档必须匹配,该选项下的查询条件,相当于逻辑运算的 AND,且参与文档相关度的评分。
  5. should:文档可以匹配 should 选项下的查询条件也可以不匹配,相当于逻辑运算的 OR,且参与文档相关度的评分。
  6. must_not:与 must 相反,匹配该选项下的查询条件的文档不会被返回;需要注意的是,must_not 语句不会影响评分,它的作用只是将不相关的文档排除。
  7. filter:和 must 一样,匹配 filter 选项下的查询条件的文档才会被返回,但是 filter 不评分,只起到过滤功能,与 must_not 相反。
  8. """
  9. # 例子
  10. {
  11.   "query": {
  12.     "bool": {
  13.       "filter": {
  14.         "term": { "status": 1 } # 必须status为1,但是不评分
  15.       },
  16.       "must_not": {
  17.         "range": { "price": { "gte": 70 } }  # print必须不大于等于70
  18.       },
  19.       "must": {
  20.         "match": { "title": "java" }  # 必须模糊匹配标题title包含java的内容  
  21.       },
  22.       "should": [
  23.         {
  24.           "match": { "description": "虚拟机" }  # 如果description包含虚拟机也匹配
  25.         },
  26.         {
  27.           "match": { "content": "计算公式" }  # 如果content包含计算公式也匹配
  28.         }
  29.       ]
  30.     }
  31.   }
  32. }
  33. """
  34. 控制精度
  35. must 语句必须匹配,但有多少 should 语句应该匹配呢?默认情况下,没有 should 语句是必须匹配的,只有一个例外,那就是当没有 must 语句的时候,至少有一个 should 语句必须匹配。
  36. 此外可以通过 minimum_should_match 参数控制需要匹配的 should 语句的数
  37. 计算规则
  38. bool 查询采用“匹配越多越好(more_matches_is_better)”的机制,因此满足 must 和 should 子句的文档将会合并起来计算分值。
  39. 在 filter 子句查询中,分值将会都返回 0。
  40. must_not 子句并不影响得分,它们存在的意义是排除已经被包含的文档。
  41. 如上所述,bool 查询的计算得分主要是 must 和 should 子句,它们的计算规则是,把所有符合 must 和 should 的子句得分加起来,然后乘以匹配子句的数量,再除以子句的总数。
  42. """
  43. # 个人方法记录:
  44. def diffWordOrQuery(field, size, texts, boolnext=[], boolnext2=[]):
  45.     """
  46.     作用: 构建bool查询query查询体
  47.     field:str.要检索的字段
  48.     size:int.单次检索要返回的数量
  49.     texts:list.对检索文本进行分词后的词列表
  50.     boolnext:list.bool的下一级key,对每个texts要采取的匹配策略
  51.     boolnext2:list.bool的下下一级key,对应match、term、range
  52.     """
  53.     if len(boolnext) < len(texts):
  54.         for i in range(len(texts) - len(boolnext)):
  55.             boolnext.append("should")
  56.     if len(boolnext2) < len(texts):
  57.         for i in range(len(texts) - len(boolnext2)):
  58.             boolnext2.append("should")
  59.     body = {
  60.         "query": {
  61.             "bool": {
  62.             },
  63.         },
  64.         "size": size,
  65.     }
  66.     for i, text in enumerate(texts):
  67.         if text == " ":
  68.             continue
  69.         method = boolnext[i]
  70.         method2 = boolnext2[i]
  71.         sonlst = body["query"]["bool"].get(method, None)
  72.         if not sonlst:
  73.             body["query"]["bool"][method] = {method2: {field: text}}
  74.         else:
  75.             son = body["query"]["bool"][method]
  76.             if type(son) == dict:
  77.                 for key1, value1 in son.items():
  78.                     for key2, value2 in value1.items():
  79.                         body["query"]["bool"][method] = [{key1: {key2: value2}}, {method2: {field: text}}]
  80.             else:
  81.                 son.append({method2: {field: text}})
  82.     return body
  83. texts = ["阅读", "语文", "英语", "数学", "政治"]
  84. boolnext = ["must", "must_not", "must"]
  85. boolnext2 = ["term", "match"]
  86. body = diffWordOrQuery("title", 50, texts, boolnext, boolnext2)
  87. print(body)
复制代码
来源:https://www.cnblogs.com/moyezq/p/17022844.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具