百木园-与人分享,
就是让自己快乐。

Python elasticsearch 使用心得

一、配置

python == 3.6/3.8
# 更高版本的elasticsearch会出现doc_type被统一成_doc导致旧版语句报错的情况
pip install elasticsearch==7.8.0

二、连接es

from elasticsearch import Elasticsearch
es = Elasticsearch(\'ip:port\')

三、查看索引是否存在,删除索引

# 浏览器查看索引
# ip:路由地址;port:运行端口(默认9200);index_name:要查看
# 查看所有索引
http://ip:port/_cat/indices?v&pretty
# 查看单个索引
http://ip:port/index_name/_settings?pretty
# 查看单个索引的数据结构
http://ip:port/index_name/?pretty
# python查看elasticsearch是否存在
# es.indices.exists(index=\"index_name\")
# 删除索引
# es.indices.delete(index=\'index_name\', ignore=[400, 404])

三、创建索引与映射

# 索引参数设置
# 索引的静态参数一旦被设置,不能改变;动态参数可以改变
def create_index(es, index_name):
    settings = {
        \'settings\':
            {
                \"number_of_shards\": 5,  # 设置主索引的主分片数,静态参数
                \"number_of_replicas\": 0,  # 设置主索引的副本数,动态参数
                \"max_result_window\": 10000000,  # 设置一次检索最大返回数量
                \"track_total_hits\": True,  # 使最大返回设置生效的参数
            }
    }

    if es.indices.exists(index_name):
        print(u\"%s 已存在\" % index_name)
    else:
        es.indices.create(index=index_name, body=settings)
        print(index_name + \"索引创建成功\")
res = es.indices.create(index=\'index_name\', ignore=400)
print(res)


# 创建映射(索引内每一个字段的设置)
\"\"\"
分词器主要有两种情况会被使用:
第一种是插入文档时,将text类型的字段做分词然后插入倒排索引,对应analyzer
第二种就是在查询时,先对要查询的text类型的输入做分词,再去倒排索引搜索,对应search_analyzer
如果想要让 索引 和 查询 时使用不同的分词器,ElasticSearch也是能支持的,只需要在字段上加上search_analyzer参数
在索引时,只会去看字段有没有定义analyzer,有定义的话就用定义的,没定义就用ES预设的
在查询时,会先去看字段有没有定义search_analyzer,如果没有定义,就去看有没有analyzer,再没有定义,才会去使用ES预设的
\"\"\"
mapping = {
    \'properties\': {
        # 简单设置
        \'title\': {
            \'type\': \'string\',
            \'analyzer\': \'jieba\',
        },
        # 较复杂的设置
        \'content\': {
            \'include_in_all\': True,  # 控制_all查询时是否需要查询该字段,默认True,若是false将不会被_all查询
            \'analyzer\': \'jieba\',  # 查询和索引统一的分词器
            # \'searchAnalyzer\': \'jieba\',  # 单独设置查询分词器
            \'index\': \"analyzed\",  # 控制字段怎样建索引或查询。no不能被查询;not_analyzed只存储原始值,不分词;analyzed分词存储
            \'boost\': 2,  # 控制该字段的查询权重,大于1会增加相对权重
            \'term_vector\': \'with_positions_offsets\',  # 存储完整的term vector信息,包括field terms、position、offset
            \'type\': \'string\',  # 旧版支持。从ElasticSearch 5.x开始不再支持string,由text和keyword类型替代。
        },
    }
}
# 设置mapping信息:可以指定字段的类型、是否进行分词、默认值、是否被索引
# 分词器analyzer和搜索分词器search_analyzer。ik_max_word为默认的英文分词器,jieba等其他分词器需要额外安装。
result = es.indices.put_mapping(index=\'index_name\', doc_type=\'doc\', body=mapping)
print(result)

四、查询索引

1、match_all查询所有

body = {
        \"query\": {
            \"match_all\": {},
        },
        \"size\": 50,  # size不设置会默认返回5条
    }
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基本一样,区别是它不考虑顺序
# term是代表完全匹配,即不进行分词器分析,文档中必须包含整个搜索的词汇
body = {
  \"query\": {
    \"term\": {
      \"content\": \"汽车保养\"
    \"from\": 1,  # 从第几个开始返回
    \"size\": 30,  # 一次返回多少个
    }
  }
}

# match 分词,部分匹配查询,包含文本分词后的一个或多个词即符合条件
body = {
    \"query\": {
        \"match\": {\"title\": \"宝马法拉利兰博基尼\"},
    },
}

# match_phrase  分词,完全匹配查询,包含文本分词后的所有词才符合条件,且匹配词的顺序必须完全按照分词前的顺序
# 例如分词后为宝马、法拉利、兰博基尼,匹配顺序宝马必须在法拉利之前,法拉利必须在兰博基尼之前
body = {
    \"query\": {
        \"match_phrase\": {\"title\": \"宝马法拉利兰博基尼\"},
    },
}

# query_string,分词,不考虑顺序
body = {
    \"query\": {
        \"query_string\": {
            \"fields\": [\"title\", \"content\"],
            \"query\": text,
        }
    }
}

3、bool组合查询

\"\"\"
bool能将多个简单查询组合起来。
使用 must、should、must_not、filter 选项来表示简单查询之间的逻辑,每个选项都可以出现 0 次到多次。
must:文档必须匹配,该选项下的查询条件,相当于逻辑运算的 AND,且参与文档相关度的评分。
should:文档可以匹配 should 选项下的查询条件也可以不匹配,相当于逻辑运算的 OR,且参与文档相关度的评分。
must_not:与 must 相反,匹配该选项下的查询条件的文档不会被返回;需要注意的是,must_not 语句不会影响评分,它的作用只是将不相关的文档排除。
filter:和 must 一样,匹配 filter 选项下的查询条件的文档才会被返回,但是 filter 不评分,只起到过滤功能,与 must_not 相反。
\"\"\"
# 例子
{
  \"query\": {
    \"bool\": {
      \"filter\": {
        \"term\": { \"status\": 1 } # 必须status为1,但是不评分
      },
      \"must_not\": {
        \"range\": { \"price\": { \"gte\": 70 } }  # print必须不大于等于70
      },
      \"must\": {
        \"match\": { \"title\": \"java\" }  # 必须模糊匹配标题title包含java的内容  
      },
      \"should\": [
        {
          \"match\": { \"description\": \"虚拟机\" }  # 如果description包含虚拟机也匹配
        },
        {
          \"match\": { \"content\": \"计算公式\" }  # 如果content包含计算公式也匹配
        }
      ]
    }
  }
}
\"\"\"
控制精度
must 语句必须匹配,但有多少 should 语句应该匹配呢?默认情况下,没有 should 语句是必须匹配的,只有一个例外,那就是当没有 must 语句的时候,至少有一个 should 语句必须匹配。
此外可以通过 minimum_should_match 参数控制需要匹配的 should 语句的数
计算规则
bool 查询采用“匹配越多越好(more_matches_is_better)”的机制,因此满足 must 和 should 子句的文档将会合并起来计算分值。
在 filter 子句查询中,分值将会都返回 0。
must_not 子句并不影响得分,它们存在的意义是排除已经被包含的文档。
如上所述,bool 查询的计算得分主要是 must 和 should 子句,它们的计算规则是,把所有符合 must 和 should 的子句得分加起来,然后乘以匹配子句的数量,再除以子句的总数。
\"\"\"
# 个人方法记录:
def diffWordOrQuery(field, size, texts, boolnext=[], boolnext2=[]):
    \"\"\"
    作用: 构建bool查询query查询体
    field:str.要检索的字段
    size:int.单次检索要返回的数量
    texts:list.对检索文本进行分词后的词列表
    boolnext:list.bool的下一级key,对每个texts要采取的匹配策略
    boolnext2:list.bool的下下一级key,对应match、term、range
    \"\"\"
    if len(boolnext) < len(texts):
        for i in range(len(texts) - len(boolnext)):
            boolnext.append(\"should\")
    if len(boolnext2) < len(texts):
        for i in range(len(texts) - len(boolnext2)):
            boolnext2.append(\"should\")
    body = {
        \"query\": {
            \"bool\": {
            },
        },
        \"size\": size,
    }
    for i, text in enumerate(texts):
        if text == \" \":
            continue
        method = boolnext[i]
        method2 = boolnext2[i]
        sonlst = body[\"query\"][\"bool\"].get(method, None)
        if not sonlst:
            body[\"query\"][\"bool\"][method] = {method2: {field: text}}
        else:
            son = body[\"query\"][\"bool\"][method]
            if type(son) == dict:
                for key1, value1 in son.items():
                    for key2, value2 in value1.items():
                        body[\"query\"][\"bool\"][method] = [{key1: {key2: value2}}, {method2: {field: text}}]
            else:
                son.append({method2: {field: text}})
    return body


texts = [\"阅读\", \"语文\", \"英语\", \"数学\", \"政治\"]
boolnext = [\"must\", \"must_not\", \"must\"]
boolnext2 = [\"term\", \"match\"]
body = diffWordOrQuery(\"title\", 50, texts, boolnext, boolnext2)
print(body)

来源:https://www.cnblogs.com/moyezq/p/17022844.html
本站部分图文来源于网络,如有侵权请联系删除。

未经允许不得转载:百木园 » Python elasticsearch 使用心得

相关推荐

  • 暂无文章