# -*- coding: UTF-8 -*-
from gm_rpcd.all import bind
from search.utils.service import recall_sku, recall_sku_by_new_search_analyze, SMARTRANK_SORT
from gm_types.gaia import SERVICE_ORDER_TYPE
from gm_types.doris import RANK_MODE
from recommend.utils.device import get_realtime_interest
from libs.algorithms import variousness, region_division
from libs.debug import pretty_json
from libs.es import es_query
from search.utils.sku import recall_sku_pure, realtime_recall_sku_pure
from hera.services import check_city_in_whitelist
import functools
import collections
import traceback
import logging
import json
import random
import hashlib
from libs.error import logging_exception
from libs.cache import redis_client
from libs.cache import redis_client2
from libs.es import es_query, get_highlight_query_analyzer, es_index_adapt, es_msearch
from django.conf import settings
# from search.views.content_aggre import process_sorting
from search.utils.service import process_sorting, process_filters
from search.utils.sku import _get_service_item_info, service_query_break_up
from search.utils.service import recommed_service_category_device_id, get_tag_size_by_score
import zstd
from search.utils.sku import _get_service_item_info, service_query_break_up
from gm_types.gaia import TAG_TYPE
from gm_types.gaia import USER_TYPE
from gm_types.doris import CARD_TYPE

logger = logging.getLogger(__name__)

MAX_LOAD = 200
GROUP_SIZE = 10
variousness_per_10 = functools.partial(variousness, variety_size=GROUP_SIZE)


def _get_query_sku_ids(redis_service_sr_key, city_service_dict, sku_ids, org_ids, doctor_ids, sku_list, inner_hits,
                       highlight_list, service_dict, service_ids, ori_size):
    try:
        if len(city_service_dict) > 0:
            sorted_city_service_id_list = sorted(city_service_dict.keys(),
                                                 key=lambda item_key: -1 if city_service_dict[
                                                                                item_key] is None else float(
                                                     city_service_dict[item_key]), reverse=True)
            for service_id in sorted_city_service_id_list:
                if city_service_dict[service_id]:
                    _get_service_item_info(sku_ids=sku_ids, org_ids=org_ids, doctor_ids=doctor_ids, sku_list=sku_list,
                                           inner_hits=inner_hits, highlight_list=highlight_list,
                                           item=service_dict[service_id], service_ids=service_ids)
                    if len(sku_ids) >= ori_size:
                        break

        return True
    except:
        logger.error("catch exception,err_log:%s" % traceback.format_exc())
        return False


# @desc 搜索spu下降到sku
# @wiki http://wiki.gengmei.cc/pages/viewpage.action?pageId=4151204
# @rd 郑伟
# @param  query                          搜索词
# @param  user_city_tag_id               用户所在城市
# @param  offset                         起始页面
# @param  size                           返回行数
# @param  sort_type                      排序类型
# @param  filters                        过滤条件
# @param  sort_params                    排序条件
# @date 20170709
@bind('dymas/search/query_sku')
def query_sku(query='', user_city_tag_id=None, offset=0, size=2,
              sort_type=SERVICE_ORDER_TYPE.DEFAULT, filters={}, sort_params={}, or_filters=[], query_type="default"):
    if sort_type == SERVICE_ORDER_TYPE.DEFAULT_REALTIME:
        device_id = sort_params['device_id']
        interest_tag = get_realtime_interest(device_id)
        if interest_tag:
            sort_params['interest_tags'] = [interest_tag]
    if user_city_tag_id is not None:
        sort_params['user_city_tag_id'] = user_city_tag_id

    # 同一搜索场景下已读美购列表
    have_read_service_list = list()
    # is_service_cpcquery_sku_weight = False
    device_id = sort_params["device_id"] if "device_id" in sort_params else ""
    ori_size = size
    sku_is_promote = list()

    is_service_test = False
    ctr_estimate_device_id_key = "doris:ctr_estimate:device_id_list"
    if sort_type == SERVICE_ORDER_TYPE.DEFAULT:
        device_id = sort_params["device_id"] if "device_id" in sort_params else ""
        if device_id and redis_client.sismember(ctr_estimate_device_id_key,device_id):
            is_service_test = True

    if device_id is None:
        device_id = ""

    have_read_redis_key = ""
    if len(device_id) == 0 and query and offset > 0:
        have_read_redis_key = "doris:service_search_have_read:query_type:" + query_type + ":query:" + query + ":offset:" + str(
            offset - size)
    else:
        have_read_redis_key = "doris:service_search_have_read:query_type:" + query_type + ":device_id:" + device_id
    redis_read_data = redis_client.get(have_read_redis_key)
    if redis_read_data and offset > 0:
        have_read_service_list = json.loads(redis_read_data)

    size = 100 if size < 100 else size
    res = recall_sku(
        query=query,
        offset=0,
        size=size,
        sort_type=sort_type,
        filters=filters,
        sort_params=sort_params,
        or_filters=or_filters,
        weight_service_cpc=True,
        have_read_service_list=have_read_service_list,
        is_service_test=is_service_test
    )

    # 根据bd反馈需要全词匹配召回的query
    need_total_match_query_list = ["深圳福华"]

    if len(res["hits"]["hits"]) == 0 and query not in need_total_match_query_list:
        res = recall_sku_by_new_search_analyze(query=query,
                                               offset=0,
                                               size=size,
                                               sort_type=sort_type,
                                               filters=filters,
                                               sort_params=sort_params,
                                               or_filters=or_filters, have_read_service_list=have_read_service_list)
        # res = recall_sku(
        #     query=query,
        #     offset=0,
        #     size=size,
        #     sort_type=sort_type,
        #     filters=filters,
        #     sort_params=sort_params,
        #     or_filters=or_filters,
        #     is_ctr_estimate=is_ctr_estimate,
        #     have_read_service_list=have_read_service_list,
        #     recall_again=True
        # )
        logger.info("sku query word:%s recall again,sort_type:%s,filters:%s,sort_params:%s,or_filters:%s,hits len:%d",
                    str(query).encode("utf-8"), str(sort_type).encode("utf-8"), str(filters).encode("utf-8"),
                    str(sort_params).encode("utf-8"), str(or_filters).encode("utf-8"), len(res["hits"]["hits"]))

    service_ids = []
    sku_ids = []
    org_ids = []
    doctor_ids = []
    res_hit = res["hits"]["hits"]
    sku_list = []
    highlight_list = []
    inner_hits = []

    if sort_type != SERVICE_ORDER_TYPE.DEFAULT:
        for item in res_hit:
            # sku_ids,org_ids,doctor_ids,sku_list,inner_hits,highlight_list,item,service_ids
            _get_service_item_info(sku_ids=sku_ids, org_ids=org_ids, doctor_ids=doctor_ids, sku_list=sku_list,
                                   inner_hits=inner_hits, highlight_list=highlight_list,
                                   item=item, service_ids=service_ids)
            if len(sku_ids) >= ori_size:
                break
    else:
        # 主要服务于简写命中的(目前主要服务于同城)
        high_weight_same_city_same_key_val_dict = dict()
        same_city_same_key_val_dict = dict()
        nearby_city_same_key_val_dict = dict()
        other_city_same_key_val_dict = dict()
        have_read_key_set = set()

        same_city_begin = True
        nearby_city_begin = True
        other_city_begin = True
        get_nearby_city_data = False
        get_hight_weight_same_city_data = False

        for item in res_hit:
            if int(item["sort"][3]) == 2:
                if int(item["sort"][5]) == 1000:
                    service_query_break_up(sku_ids=sku_ids, org_ids=org_ids, doctor_ids=doctor_ids, sku_list=sku_list,
                                           inner_hits=inner_hits, highlight_list=highlight_list, item=item,
                                           have_read_key_set=have_read_key_set, size=ori_size,
                                           same_key_val_dict=high_weight_same_city_same_key_val_dict,
                                           service_ids=service_ids)
                    get_hight_weight_same_city_data = True
                else:
                    if len(sku_ids) == 0:
                        same_city_begin = False
                    service_query_break_up(sku_ids=sku_ids, org_ids=org_ids, doctor_ids=doctor_ids, sku_list=sku_list,
                                           inner_hits=inner_hits, highlight_list=highlight_list, item=item,
                                           have_read_key_set=have_read_key_set, size=ori_size,
                                           same_key_val_dict=same_city_same_key_val_dict,
                                           same_key_val_user_first=same_city_begin,
                                           dispose_same_key_val_dict=high_weight_same_city_same_key_val_dict,
                                           service_ids=service_ids)
                    same_city_begin = False
                    get_hight_weight_same_city_data = False
            elif int(item["sort"][3]) == 1:
                if len(sku_ids) == 0:
                    nearby_city_begin = False
                service_query_break_up(sku_ids=sku_ids, org_ids=org_ids, doctor_ids=doctor_ids, sku_list=sku_list,
                                       inner_hits=inner_hits, highlight_list=highlight_list, item=item,
                                       have_read_key_set=have_read_key_set, size=ori_size,
                                       same_key_val_dict=nearby_city_same_key_val_dict,
                                       same_key_val_user_first=nearby_city_begin,
                                       dispose_same_key_val_dict=same_city_same_key_val_dict, service_ids=service_ids)
                nearby_city_begin = False
                get_nearby_city_data = True
                get_hight_weight_same_city_data = False
            elif int(item["sort"][3]) == 0:
                if len(sku_ids) == 0:
                    other_city_begin = False
                if get_nearby_city_data:
                    service_query_break_up(sku_ids=sku_ids, org_ids=org_ids, doctor_ids=doctor_ids, sku_list=sku_list,
                                           inner_hits=inner_hits, highlight_list=highlight_list, item=item,
                                           have_read_key_set=have_read_key_set, size=ori_size,
                                           same_key_val_dict=other_city_same_key_val_dict,
                                           same_key_val_user_first=other_city_begin,
                                           dispose_same_key_val_dict=nearby_city_same_key_val_dict,
                                           service_ids=service_ids)
                elif get_hight_weight_same_city_data:
                    service_query_break_up(sku_ids=sku_ids, org_ids=org_ids, doctor_ids=doctor_ids, sku_list=sku_list,
                                           inner_hits=inner_hits, highlight_list=highlight_list, item=item,
                                           have_read_key_set=have_read_key_set, size=ori_size,
                                           same_key_val_dict=other_city_same_key_val_dict,
                                           same_key_val_user_first=other_city_begin,
                                           dispose_same_key_val_dict=high_weight_same_city_same_key_val_dict,
                                           service_ids=service_ids)
                else:
                    service_query_break_up(sku_ids=sku_ids, org_ids=org_ids, doctor_ids=doctor_ids, sku_list=sku_list,
                                           inner_hits=inner_hits, highlight_list=highlight_list, item=item,
                                           have_read_key_set=have_read_key_set, size=ori_size,
                                           same_key_val_dict=other_city_same_key_val_dict,
                                           same_key_val_user_first=other_city_begin,
                                           dispose_same_key_val_dict=same_city_same_key_val_dict,
                                           service_ids=service_ids)
                other_city_begin = False

            if len(sku_ids) >= ori_size:
                break

        read_over_key_num = 0
        need_dispose_same_key_dict = dict()
        if len(same_city_same_key_val_dict) > 0:
            need_dispose_same_key_dict = same_city_same_key_val_dict
        elif len(nearby_city_same_key_val_dict) > 0:
            need_dispose_same_key_dict = nearby_city_same_key_val_dict
        elif len(other_city_same_key_val_dict) > 0:
            need_dispose_same_key_dict = other_city_same_key_val_dict
        elif len(high_weight_same_city_same_key_val_dict) > 0:
            need_dispose_same_key_dict = high_weight_same_city_same_key_val_dict

        if len(sku_ids) < ori_size and read_over_key_num < len(need_dispose_same_key_dict):
            read_over_key_num = service_query_break_up(sku_ids=sku_ids, org_ids=org_ids, doctor_ids=doctor_ids,
                                                       sku_list=sku_list, inner_hits=inner_hits,
                                                       highlight_list=highlight_list, item=None,
                                                       have_read_key_set=have_read_key_set, size=ori_size,
                                                       same_key_val_dict=need_dispose_same_key_dict,
                                                       same_key_val_user_first=True,
                                                       dispose_same_key_val_dict=need_dispose_same_key_dict,
                                                       service_ids=service_ids)

    have_read_service_list.extend(service_ids)

    if len(device_id) == 0 and query:
        have_read_redis_key = "doris:service_search_have_read:query_type:" + query_type + ":query:" + query + ":offset:" + str(
            offset)
    redis_client.set(have_read_redis_key, json.dumps(have_read_service_list))
    redis_client.expire(have_read_redis_key, 10 * 60)

    if sort_type in SMARTRANK_SORT:
        mode = RANK_MODE.CPC
    else:
        mode = RANK_MODE.DEFAULT
    return {"sku_ids": sku_ids,
            'hospital_ids': org_ids,
            'doctor_ids': doctor_ids,
            'sku_list': sku_list,
            "rank_mode": mode,
            "total": res["hits"]["total"],
            "highlight": highlight_list,
            "inner_hits": inner_hits,
            "is_cpc": sku_is_promote,
            "service_ids": service_ids
            }


# @desc 高级搜索接口
# @rd 郑伟
# @param  query                          搜索词
# @param  user_city_tag_id               用户所在城市
# @param  offset                         起始页面
# @param  size                           返回行数
# @param  sort_type                      排序类型
# @param  filters                        过滤条件
# @param  sort_params                    排序条件
# @date 20180409

@bind('doris/search/as_query_sku')
def as_query_sku(query='', user_city_tag_id=None, offset=0, size=10,
                 sort_type=SERVICE_ORDER_TYPE.DEFAULT, filters={}, sort_params={}, or_filters=[], must_filters=False,
                 inner_hits=False, have_get_service_ids=[]):
    try:
        if user_city_tag_id is not None:
            sort_params['user_city_tag_id'] = user_city_tag_id
        tail = offset + size
        sku_ids = []
        sku_is_promote = []
        if tail < MAX_LOAD:
            res = recall_sku(
                query=query,
                offset=0,
                size=MAX_LOAD,
                sort_type=sort_type,
                filters=filters,
                sort_params=sort_params,
                or_filters=or_filters,
                fields=['id', 'merchant_doctor_id', "doctor.hospital.city_tag_id", "nearby_city_tags.tag_id",
                        "new_sku_special"],
                must_filters=must_filters,
                inner_hits=inner_hits
            )
            skus = []
            res_hit = res["hits"]["hits"]
            for item in res_hit:
                if 'inner_hits' in item:
                    hit = item['inner_hits']
                    if inner_hits == True and hit["new_sku_special"]['hits']["total"] > 0:
                        sku = hit["new_sku_special"]['hits']['hits'][0]
                    else:
                        sku = hit['sku_list']['hits']['hits'][0]

                    sku_id = sku['_source']['sku_id']
                    merchant_id = item['_source']['merchant_doctor_id']
                    city = item['_source']['doctor']['hospital']['city_tag_id']
                    nearby = [row['tag_id'] for row in item['_source'].get('nearby_city_tags', [])]
                    is_promote = item['_source'].get("is_promote", False)
                    skus.append({"id": sku_id,
                                 "group": merchant_id,
                                 "city": city,
                                 "nearby": nearby,
                                 "is_promote": is_promote})
            division_skus = region_division(skus, user_city_tag_id)
            division_reranks = map(variousness_per_10, division_skus)
            sku_rerank = [sku for skus in division_reranks for sku in skus]
            sku_ids = [sku['id'] for sku in sku_rerank[offset:tail]]
            sku_is_promote = [sku['is_promote'] for sku in sku_rerank[offset:tail]]

        if len(sku_ids) == 0:
            res = recall_sku(
                query=query,
                offset=offset,
                size=size,
                sort_type=sort_type,
                filters=filters,
                sort_params=sort_params,
                or_filters=or_filters,
                fields=['id'],
                inner_hits=inner_hits,
                have_read_service_list=have_get_service_ids
            )
            res_hit = res["hits"]["hits"]
            for item in res_hit:
                if 'inner_hits' in item:
                    hit = item['inner_hits']
                    if inner_hits == True:
                        sku = hit["new_sku_special"]['hits']['hits'][0]
                    else:
                        sku = hit['sku_list']['hits']['hits'][0]
                    sku_id = sku['_source']['sku_id']
                    sku_ids.append(sku_id)
                    is_promote = item['_source'].get("is_promote", False)
                    sku_is_promote.append(is_promote)

        if sort_type in SMARTRANK_SORT:
            mode = RANK_MODE.CPC
        else:
            mode = RANK_MODE.DEFAULT

        return {"sku_ids": sku_ids,
                "rank_mode": mode,
                "is_cpc": sku_is_promote}
    except:
        logging_exception()
        logging.error("catch exception,err_msg:%s" % traceback.format_exc())
        return {"sku_ids": [], "rank_mode": RANK_MODE.DEFAULT, "is_cpc": []}


@bind('doris/search/as_query_sku_pure')
def as_query_sku_pure(query='', user_city_tag_id=None, offset=0, size=10,
                      sort_type=SERVICE_ORDER_TYPE.DEFAULT, filters={}, sort_params={}, or_filters=[]):
    """基于sku mapping的es高级搜索"""

    if user_city_tag_id is not None:
        sort_params['user_city_tag_id'] = user_city_tag_id

    tail = offset + size
    sku_ids = []

    if tail < MAX_LOAD:
        res = recall_sku_pure(
            query=query,
            offset=0,
            size=MAX_LOAD,
            sort_type=sort_type,
            filters=filters,
            sort_params=sort_params,
            or_filters=or_filters,
            fields=['id', 'merchant_doctor_id', "doctor.hospital.city_tag_id", "nearby_city_tags.tag_id"]
        )
        skus = []
        res_hit = res["hits"]["hits"]

        for item in res_hit:
            item_src = item['_source']
            sku_id = item_src['id']
            merchant_id = item_src['merchant_doctor_id']
            city = item_src['doctor']['hospital']['city_tag_id']
            nearby = [row['tag_id'] for row in item_src['nearby_city_tags']]
            skus.append({"id": sku_id,
                         "group": merchant_id,
                         "city": city,
                         "nearby": nearby})

        division_skus = region_division(skus, user_city_tag_id)
        division_reranks = map(variousness_per_10, division_skus)
        sku_rerank = [sku for skus in division_reranks for sku in skus]
        sku_ids = [sku['id'] for sku in sku_rerank[offset:tail]]

    if len(sku_ids) == 0:
        res = recall_sku_pure(
            query=query,
            offset=offset,
            size=size,
            sort_type=sort_type,
            filters=filters,
            sort_params=sort_params,
            or_filters=or_filters,
            fields=['id']
        )
        res_hit = res["hits"]["hits"]
        for item in res_hit:
            item_src = item['_source']
            sku_id = item_src['id']
            sku_ids.append(sku_id)

    if sort_type in SMARTRANK_SORT:
        mode = RANK_MODE.CPC
    else:
        mode = RANK_MODE.DEFAULT

    return {"sku_ids": sku_ids,
            "rank_mode": mode}


def calc_real_offset_size(obj_type, special_id, user_city_tag_id=None, offset=0, size=10, floor_id=None):
    """
    :param obj_type: sku|service 从哪个索引获取数据

    获取一页数据的方式: 该页里设置的位置的sku_ids + es 取出未设置位置的剩余sku_ids
    1. 计算该页前共有多少设置了位置的sku [prev_posed_cnt]
    2. 计算该页有多少设置了位置的sku [curr_posed_cnt], 并取出这些sku及其位置 [posed_sku_spinfo {pos: sku_id, ...}]
    3. 计算从es search 的真实offset和真实size, [real_offset = offset - prev_posed_cnt, real_size = size - curr_posed_cnt]
    4. 从es获取剩余sku_ids
    5. 合并成一个sku_ids 列表
    """
    try:
        if user_city_tag_id is None:
            return offset, size, {}
        prev_posed_filter = {
            "_source": False,
            "query": {
                "bool": {
                    "must": [
                        {
                            "nested": {
                                "path": "new_sku_special",
                                "query": {
                                    "bool": {
                                        "must": [
                                            {"term": {"new_sku_special.id": special_id}},
                                            {"term": {"new_sku_special.has_pos": True}},
                                            {"range": {"new_sku_special.position": {"lte": offset}}}
                                        ]
                                    }
                                }
                            }
                        },
                        {"term": {"doctor.hospital.city_tag_id": user_city_tag_id}},
                        {'term': {'is_online': True}}
                    ]
                }
            }
        }
        if floor_id:
            prev_posed_filter["query"]["bool"]["must"].append({'term': {'floor_id': floor_id}})
        prev_posed = es_query(obj_type, body=prev_posed_filter, offset=0, size=0)
        prev_posed_cnt = prev_posed['hits']['total']

        curr_pos_filter = {
            "_source": ['id'],
            "query": {
                "bool": {
                    "must": [
                        {
                            "nested": {
                                "path": "new_sku_special",
                                "query": {
                                    "bool": {
                                        "must": [
                                            {"term": {"new_sku_special.id": special_id}},
                                            {"term": {"new_sku_special.has_pos": True}},
                                            {"range": {
                                                "new_sku_special.position": {"gt": offset, "lte": offset + size}}}
                                        ]
                                    }
                                },
                                "inner_hits": {}
                            }
                        },
                        {"term": {"doctor.hospital.city_tag_id": user_city_tag_id}},
                        {'term': {'is_online': True}}
                    ]
                }
            }
        }
        if floor_id:
            curr_pos_filter["query"]["bool"]["must"].append({'term': {'floor_id': floor_id}})
        curr_pos = es_query(obj_type, body=curr_pos_filter, offset=0, size=size)
        curr_pos_cnt = curr_pos['hits']['total']
        posed_sku_spinfo = {}
        if curr_pos_cnt:
            for res_hit in curr_pos['hits']['hits']:

                sp_hit = res_hit['inner_hits']
                # sku_id = sp_hit['special']['hits']['hits'][0]['_id']
                sp_info = sp_hit['new_sku_special']['hits']['hits'][0]['_source']
                sku_id = sp_info['sku_id']
                if posed_sku_spinfo.get(sp_info['position']):
                    posed_sku_spinfo[sp_info['position']].append(sku_id)
                else:
                    posed_sku_spinfo[sp_info['position']] = [sku_id, ]

        real_offset = offset - prev_posed_cnt
        real_size = size - curr_pos_cnt
        # 按position 从小到大排序
        sorted_posed_sku_spinfo = collections.OrderedDict(sorted(posed_sku_spinfo.items(), key=lambda v: v[0]))

        logging.info("get curr_pos_filter:%s" % curr_pos_filter)
        return real_offset, real_size, sorted_posed_sku_spinfo
    except:
        logging_exception()
        logger.error("catch exception,err_msg:%s" % traceback.format_exc())
        return offset, size, {}


def calc_real_offset_size_sku(obj_type, special_id, user_city_tag_id=None, offset=0, size=10, floor_id=None):
    """
    :param obj_type: sku|service 从哪个索引获取数据

    获取一页数据的方式: 该页里设置的位置的sku_ids + es 取出未设置位置的剩余sku_ids
    1. 计算该页前共有多少设置了位置的sku [prev_posed_cnt]
    2. 计算该页有多少设置了位置的sku [curr_posed_cnt], 并取出这些sku及其位置 [posed_sku_spinfo {pos: sku_id, ...}]
    3. 计算从es search 的真实offset和真实size, [real_offset = offset - prev_posed_cnt, real_size = size - curr_posed_cnt]
    4. 从es获取剩余sku_ids
    5. 合并成一个sku_ids 列表
    """
    try:
        if user_city_tag_id is None:
            return offset, size, {}
        prev_posed_filter = {
            "_source": False,
            "query": {
                "bool": {
                    "must": [
                        {
                            "nested": {
                                "path": "special",
                                "query": {
                                    "bool": {
                                        "must": [
                                            {"term": {"special.id": special_id}},
                                            {"term": {"special.has_pos": True}},
                                            {"range": {"special.position": {"lte": offset}}}
                                        ]
                                    }
                                }
                            }
                        },
                        {"term": {"doctor.hospital.city_tag_id": user_city_tag_id}},
                        {'term': {'is_online': True}}
                    ]
                }
            }
        }
        if floor_id:
            prev_posed_filter["query"]["bool"]["must"].append({'term': {'floor_id': floor_id}})
        prev_posed = es_query(obj_type, body=prev_posed_filter, offset=0, size=0)
        prev_posed_cnt = prev_posed['hits']['total']

        curr_pos_filter = {
            "_source": ['id'],
            "query": {
                "bool": {
                    "must": [
                        {
                            "nested": {
                                "path": "special",
                                "query": {
                                    "bool": {
                                        "must": [
                                            {"term": {"special.id": special_id}},
                                            {"term": {"special.has_pos": True}},
                                            {"range": {
                                                "special.position": {"gt": offset, "lte": offset + size}}}
                                        ]
                                    }
                                },
                                "inner_hits": {}
                            }
                        },
                        {"term": {"doctor.hospital.city_tag_id": user_city_tag_id}},
                        {'term': {'is_online': True}}
                    ]
                }
            }
        }
        if floor_id:
            curr_pos_filter["query"]["bool"]["must"].append({'term': {'floor_id': floor_id}})
        curr_pos = es_query(obj_type, body=curr_pos_filter, offset=0, size=size)
        curr_pos_cnt = curr_pos['hits']['total']
        posed_sku_spinfo = {}
        if curr_pos_cnt:
            for res_hit in curr_pos['hits']['hits']:

                sp_hit = res_hit['inner_hits']
                # sku_id = sp_hit['special']['hits']['hits'][0]['_id']
                sp_info = sp_hit['special']['hits']['hits'][0]['_source']
                sku_id = sp_info['sku_id']
                if posed_sku_spinfo.get(sp_info['position']):
                    posed_sku_spinfo[sp_info['position']].append(sku_id)
                else:
                    posed_sku_spinfo[sp_info['position']] = [sku_id, ]

        real_offset = offset - prev_posed_cnt
        real_size = size - curr_pos_cnt
        # 按position 从小到大排序
        sorted_posed_sku_spinfo = collections.OrderedDict(sorted(posed_sku_spinfo.items(), key=lambda v: v[0]))
        return real_offset, real_size, sorted_posed_sku_spinfo
    except:
        logging_exception()
        logger.error("catch exception,err_msg:%s" % traceback.format_exc())
        return offset, size, {}


def check_default_filter(filters):
    default_filter_whitelist = ['special_id']
    filter_keys = list(filters.keys())
    for k in default_filter_whitelist:
        if k in filter_keys:
            filter_keys.remove(k)
    for k in filter_keys:
        if not filters[k]:
            filter_keys.remove(k)
    return not bool(filter_keys)


def get_mix_floor_hits(offset=0, size=10, special_id=None, sort_type=SERVICE_ORDER_TYPE.DEFAULT,
                       sort_params={}, tag_ids=[]):
    try:
        ##先获取有位置的再获取没有位置的
        must = [
            {
                "term": {
                    "is_online": True
                }
            },
            {"nested": {"path": "sku_list", "query": {"bool": {
                "must": [{"range": {"sku_list.start_time": {"lte": "now"}}},
                         {"range": {"sku_list.end_time": {"gt": "now"}}}]}},
                        "inner_hits": {"size": 1, "sort": ["_score", {"sku_list.price": "asc"}]}}},

        ]

        should = [
            {"nested": {"path": "special",
                        "query": {"bool": {"must": [{"term": {"special.id": special_id}}]}},
                        "inner_hits": {"size": 1, "sort": ["_score", {"sku_list.price": "asc"}]}}},
            {"terms": {"closure_tag_ids": tag_ids}}
        ]
        q = {"query": {
            "function_score": {
                "functions": [
                    {"weight": 1000, "filter": {"bool": {"must": [{"nested": {"path": "special", "query": {
                        "bool": {
                            "must": [{"term": {"special.id": special_id}},
                                     {"term": {"special.has_pos": True}}]}}}}]}}}
                ],
                "query": {
                    "bool": {
                        "must": must,
                        "should": should,
                        "minimum_should_match": 1
                    }
                },
                "score_mode": "sum",
                "boost_mode": "replace"
            }
        }}
        q['sort'] = process_sorting(sort_type=sort_type, sort_params=sort_params, weight_office_score=True)
        position_skus = []
        no_position_skus = []
        position_sku_ids = []
        no_position_sku_ids = []
        curr_pos = es_query("service", q, offset=offset, size=size)
        curr_pos_cnt = curr_pos['hits']['total']
        if curr_pos_cnt:
            for res_hit in curr_pos['hits']['hits']:
                sp_hit = res_hit['inner_hits']
                if sp_hit["special"]['hits']["total"] > 0:
                    sku = sp_hit["special"]['hits']['hits'][0]
                    position = sku['_source']['position']
                else:
                    sku = sp_hit['sku_list']['hits']['hits'][0]
                    position = 0
                sku_id = sku['_source']['sku_id']
                merchant_id = res_hit['_source']['merchant_doctor_id']
                city = res_hit['_source']['doctor']['hospital']['city_tag_id']
                nearby = [row['tag_id'] for row in res_hit['_source'].get('nearby_city_tags', [])]
                is_promote = res_hit['_source'].get("is_promote", False)

                if position > 0:
                    position_skus.append({"id": sku_id,
                                          "group": merchant_id,
                                          "city": city,
                                          "nearby": nearby,
                                          "is_promote": is_promote,
                                          "position": position})
                else:
                    no_position_skus.append({"id": sku_id,
                                             "group": merchant_id,
                                             "city": city,
                                             "nearby": nearby,
                                             "is_promote": is_promote,
                                             "position": position})

        logging.info("get position_skus:%s" % position_skus)
        logging.info("get no_position_skus:%s" % no_position_skus)

        if len(position_skus) > 0:
            division_skus = region_division(position_skus, sort_params.get("user_city_tag_id", -1))
            division_reranks = map(variousness_per_10, division_skus)
            sku_rerank = [sku for skus in division_reranks for sku in skus]
            position_sku_ids = [{str(sku['id']): sku['position']} for sku in sku_rerank]
            logging.info("get posed_sku_spinfo:%s" % position_sku_ids)

        if len(no_position_skus) > 0:
            division_skus = region_division(no_position_skus, sort_params.get("user_city_tag_id", -1))
            division_reranks = map(variousness_per_10, division_skus)
            sku_rerank = [sku for skus in division_reranks for sku in skus]
            no_position_sku_ids = [{str(sku['id']): sku['position']} for sku in sku_rerank]
            logging.info("get posed_sku_spinfo:%s" % no_position_sku_ids)

        position_sku_ids.extend(no_position_sku_ids)

        if sort_type in SMARTRANK_SORT:
            mode = RANK_MODE.CPC
        else:
            mode = RANK_MODE.DEFAULT
        logging.info("get position_sku_ids:%s" % position_sku_ids)

        return position_sku_ids, mode

    except:
        logging_exception()
        logger.error("catch exception,err_msg:%s" % traceback.format_exc())
        return {}, RANK_MODE.DEFAULT


@bind('doris/search/seckill')
def seckill_query(special_id, user_city_info=None, offset=0, size=10,
                  sort_type=SERVICE_ORDER_TYPE.DEFAULT, filters={}, sort_params={}, or_filters=[]):
    """秒杀美购列表

    :param special_id:
    :param user_city_info: 用户定位的城市信息 {user_city_tag_id: 用户定位城市的tag id, user_city_id: 用户定位城市的id}
    :param offset:
    :param size:
    :param sort_type:
    :param filters:
    :param sort_params:
    :param or_filters:
    :return: {skus: {sku_id: sku id, src_type: 数据来源 op运营设置|es从es获取}, rank_mode: }
    """
    flag_default = False
    if check_default_filter(filters) and sort_type == SERVICE_ORDER_TYPE.DEFAULT:
        # 默认列表的判断, 没有选择任何过滤项和其他排序方式
        flag_default = True

    filters['special_id'] = special_id
    user_city_tag_id = None
    if user_city_info is not None:
        user_city_tag_id = user_city_info['user_city_tag_id']
        sort_params['user_city_tag_id'] = user_city_tag_id
        filters['user_city_tag_id'] = user_city_tag_id
        sort_params['in_whitelist'] = check_city_in_whitelist(user_city_info['user_city_id'])

    if flag_default and user_city_tag_id is not None:
        # 获取默认列表, 需要处理绝对位置的设置
        filters['is_posed'] = True
        real_offset, real_size, posed_sku_spinfo = calc_real_offset_size_sku(
            'sku', special_id, user_city_tag_id, offset, size,
        )
        rest_result = as_query_sku_pure(
            filters=filters, or_filters=or_filters, sort_type=sort_type, sort_params=sort_params,
            offset=real_offset, size=real_size,
        )

        skus_info = [{'sku_id': sku_id, '__src_type': 'es'} for sku_id in rest_result['sku_ids']]

        for i, sku_id in posed_sku_spinfo.items():
            skus_info.insert(i - 1 - offset, {'sku_id': sku_id, '__src_type': 'op'})
        return {'skus': skus_info, 'rank_mode': rest_result['rank_mode']}

    else:
        filters['is_posed'] = False
        rest_result = as_query_sku_pure(
            filters=filters, or_filters=or_filters, sort_type=sort_type, sort_params=sort_params,
            offset=offset, size=size,
        )
        skus_info = [{'sku_id': sku_id, '__src_type': 'es'} for sku_id in rest_result['sku_ids']]
        return {'skus': skus_info, 'rank_mode': rest_result['rank_mode']}


@bind('doris/search/special')
def special_query(special_id, user_city_info=None, floor_id=None,
                  offset=0, size=10, sort_type=SERVICE_ORDER_TYPE.DEFAULT,
                  filters={}, sort_params={}, or_filters=[], mix_floor=False):
    """专题美购列表

    :param special_id:
    :param user_city_info:
    :param offset:
    :param size:
    :param sort_type:
    :param filters:
    :param sort_params:
    :param or_filters:
    :return: {skus: {sku_id: sku id, src_type: 数据来源 op运营设置|es从es获取}, rank_mode: }
    """
    flag_default = False
    if check_default_filter(filters) and sort_type == SERVICE_ORDER_TYPE.DEFAULT:
        # 默认列表的判断, 没有选择任何过滤项和其他排序方式
        flag_default = True

    filters['special_id'] = special_id
    tag_ids = []
    if or_filters:
        tag_ids = [item.get("tag_ids", []) for item in or_filters][0]

    if floor_id:
        filters['floor_id'] = floor_id

    # fix http://sentry.igengmei.com/sentry/prod-doris/issues/2621353/
    if 'special_id' not in sort_params and special_id:
        sort_params['special_id'] = special_id

    user_city_tag_id = None
    if user_city_info is not None:
        user_city_tag_id = user_city_info['user_city_tag_id']
        sort_params['user_city_tag_id'] = user_city_tag_id
        filters['user_city_tag_id'] = user_city_tag_id
        # sort_params['in_whitelist'] = check_city_in_whitelist(user_city_info['user_city_id'])
        sort_params['in_whitelist'] = 1

    if mix_floor == True:
        result_sku_info, rank_mode = get_mix_floor_hits(offset=offset, size=size, special_id=special_id,
                                                        sort_params=sort_params,
                                                        sort_type=sort_type, tag_ids=tag_ids)

        logging.info("get result_sku_info:%s" % result_sku_info)

        skus_info = [{'sku_id': int(sku_id), '__src_type': 'es', 'position': position} for values in
                     result_sku_info for sku_id, position in values.items()]

        return {'skus': skus_info, 'rank_mode': rank_mode}

    if flag_default and user_city_tag_id is not None:

        # 获取默认列表, 需要处理绝对位置的设置
        filters['is_posed'] = True
        real_offset, real_size, posed_sku_spinfo = calc_real_offset_size(
            'service', special_id, user_city_tag_id, offset, size, floor_id,
        )
        posed_sku_ids = [sku for position, sku_id in posed_sku_spinfo.items() for sku in sku_id]
        rest_result = as_query_sku(
            filters=filters, or_filters=or_filters, sort_type=sort_type, sort_params=sort_params,
            offset=real_offset, size=real_size, must_filters=True, inner_hits=True, user_city_tag_id=user_city_tag_id,
            have_get_service_ids=posed_sku_ids
        )
        skus_info = [{'sku_id': sku_id, '__src_type': 'es', 'position': 0} for sku_id in rest_result['sku_ids']]
        posed_sku_spinfo = [(position, sku) for position, sku_id in posed_sku_spinfo.items() for sku in sku_id]
        for position, sku_id in posed_sku_spinfo:
            if sku_id not in rest_result['sku_ids']:
                skus_info.insert(position - 1 - offset, {'sku_id': sku_id, '__src_type': 'op', 'position': position})
        return {'skus': skus_info, 'rank_mode': rest_result['rank_mode']}
    else:

        filters['is_posed'] = False
        result = as_query_sku(
            filters=filters, or_filters=or_filters, sort_type=sort_type, sort_params=sort_params,
            offset=offset, size=size, must_filters=True, inner_hits=True, user_city_tag_id=user_city_tag_id
        )
        skus_info = [{'sku_id': sku_id, '__src_type': 'es', 'position': 0} for sku_id in result['sku_ids']]

        return {'skus': skus_info, 'rank_mode': result['rank_mode']}


@bind('doris/search/judge_service_cpc')
def judge_service_cpc(service_ids=[]):
    """
    统计接口判断美购是否是cpc
    :param service_ids:
    :return:
    """
    try:
        service_id_list = []
        if isinstance(service_ids, int):
            service_id_list.append(service_ids)

        if isinstance(service_ids, list):
            service_id_list = service_ids

        q = {
            "query": {
                "bool": {
                    "must": {
                        "terms": {
                            "id": service_id_list
                        }
                    }
                }
            }
        }
        res = es_query('service', q, 0, len(service_id_list))
        service_id_cpc = dict()
        res_hit = res["hits"]["hits"]
        for item in res_hit:
            service_id = item["_source"]["id"]
            is_promote = item["_source"].get("is_promote", False)
            service_id_cpc[service_id] = is_promote

        for id in service_ids:
            if id not in service_id_cpc.keys():
                service_id_cpc[id] = False
        return json.dumps(service_id_cpc)

    except:
        logging_exception()
        logger.error("catch exception,err_msg:%s" % traceback.format_exc())
        return []


@bind('doris/search/service_home_recommend')
def recommend_service_feed(device_id="", offset=0, size=10,
                           sort_type=SERVICE_ORDER_TYPE.DEFAULT,
                           filters=None, sort_params=None,
                           user_city_tag_id=None):
    try:
        """
        灰度设置、       
        0 - 4
        a, b, c
        (取device_id的哈希值)
        {'tag_score': 837.5555555555555, 'tag2': 37, 'weight': 41.85952237496425}
        """
        if device_id is None:
            device_id = ""
        filters = filters or {}
        sort_params = sort_params or {}

        org_ids = []
        doctor_ids = []
        sku_list = []
        tag_sku_ids = []
        tag_service_id = []
        tag_org_ids = []
        tag_doctor_ids = []
        service_id = []
        tag_sku_list = []
        service_smart_rank = []
        all_service_ids = list()
        scatter_service = list()
        ##灰度设置
        hash_bol = recommed_service_category_device_id(device_id=device_id)
        logging.info("get hash_bol:%s" % hash_bol)

        if hash_bol == True and sort_type == SERVICE_ORDER_TYPE.DEFAULT and len(filters) == 0:
            # ##获取用户画像的标签数据
            user_service_portrait_tags_key = "user:service_portrait_tags2:cl_id:" + str(device_id)
            if redis_client2.exists(user_service_portrait_tags_key):
                user_portrait_redis = redis_client2.hgetall(user_service_portrait_tags_key)
            else:
                new_user_service_portrait_tags_key = "user:service_coldstart_tags2"
                user_portrait_redis = redis_client2.hgetall(new_user_service_portrait_tags_key)

            user_portrait = [{"tag_score": float(score), "tag_id": int(tag)} for tag, score in
                             user_portrait_redis.items()]

            user_portrait_desc = sorted(user_portrait, key=lambda k: (k.get('tag_score', 0)), reverse=True)[:10]
            user_portrait_tag_list = [item.get("tag_id", None) for item in user_portrait_desc]

            ##获取对应的标签需要召回的个数
            tag_size = get_tag_size_by_score(user_portrait_desc)

            ##灰度和用户画像
            query_body = ""
            if len(user_portrait_tag_list) > 0:
                for tag_id in user_portrait_tag_list:
                    q = {}
                    q["query"] = {
                        "bool": {
                            "must": [
                                {
                                    "term": {
                                        "is_online": True
                                    }
                                }, {
                                    "term": {
                                        "closure_tag_ids": tag_id
                                    }
                                }, {
                                    "term": {
                                        "is_promote": True
                                    }
                                }, {
                                    "term": {
                                        "doctor.hospital.city_tag_id": sort_params[
                                            'user_city_tag_id'] if 'user_city_tag_id' in sort_params else -1

                                    }
                                }]
                        }

                    }

                    q["sort"] = process_sorting(sort_params=sort_params, sort_type=sort_type, weight_service_cpc=True)
                    q["highlight"] = get_highlight_query_analyzer(fields=["short_description"], query="")
                    q["size"] = tag_size.get(tag_id)

                    service_index_name = es_index_adapt(index_prefix=settings.ES_INDEX_PREFIX, doc_type="service",
                                                        rw="read")
                    service_header_dict = {'index': service_index_name, 'type': "service"}
                    query_body += "{}\n{}\n".format(json.dumps(service_header_dict), json.dumps(q))

                res = es_msearch(query_body, es_hosts_config=settings.ES_SERVICE_HOSTS)
                all_sku_hits = []
                if len(res) > 0 and "responses" in res:
                    for item in res["responses"]:
                        if "hits" in item and "hits" in item["hits"] and len(item["hits"]["hits"]) > 0:
                            res_hits = item["hits"]["hits"]
                            for res_hit in res_hits:
                                all_sku_hits.append(res_hit)

                for all_sku_hit in all_sku_hits:
                    if all_sku_hit["_source"]["id"] not in all_service_ids:
                        serviceid = all_sku_hit["_source"]["id"]
                        all_service_ids.append(serviceid)
                        orgids = all_sku_hit['_source']['doctor']['hospital']['id']
                        doctorids = all_sku_hit['_source']['doctor']['id']
                        skuids = all_sku_hit["_source"]["sku_list"][0]["sku_id"]
                        merchant_doctor_id = all_sku_hit["_source"]["merchant_doctor_id"]
                        skulist = {
                            'city_tag_id': all_sku_hit['_source']['doctor']['hospital']['city_tag_id'],
                            'nearby_city_tags': all_sku_hit['_source'].get('nearby_city_tags', [])
                        }
                        smartrank2 = all_sku_hit["_source"]["smart_rank2"]

                        service_smart_rank.append(
                            {"service_id": serviceid, "org_ids": orgids, "doctor_ids": doctorids, "sku_ids": skuids,
                             "sku_list": skulist, "smart_ranks": smartrank2, "group": merchant_doctor_id})
            ##根据smart_rank排序
            service_data = sorted(service_smart_rank, key=lambda k: (k.get('smart_ranks', 0)), reverse=True)
            scatter_service = variousness_per_10(service_data)
            ##商户打散
            for item in scatter_service:
                tag_service_id.append(item.get("service_id", None))
                tag_org_ids.append(item.get("org_ids", None))
                tag_doctor_ids.append(item.get("doctor_ids", None))
                tag_sku_list.append(item.get("sku_list", None))
                tag_sku_ids.append(item.get("sku_ids", None))
        # 原正常排序
        f = process_filters(filters=filters)
        q = {
            'query': {'bool': {'must': f}}

        }
        ###过滤用户画像的数据
        if len(tag_service_id) > 0:
            q["query"]["bool"]["must_not"] = {
                "terms": {
                    "id": tag_service_id
                }
            }
        # 排序规则部分
        q['sort'] = process_sorting(sort_type=sort_type, sort_params=sort_params, weight_service_cpc=True)

        logging.info("get qqq:%s" % q)
        res = es_query("service", q, offset=offset, size=size)
        if len(res) > 0:
            for item in res["hits"]["hits"]:
                service_id.append(item["_source"]["id"])
                org_ids.append(item['_source']['doctor']['hospital']['id'])
                doctor_ids.append(item['_source']['doctor']['id'])
                sku_list.append({
                    'city_tag_id': item['_source']['doctor']['hospital']['city_tag_id'],
                    'nearby_city_tags': item['_source'].get('nearby_city_tags', [])
                })
        if sort_type in SMARTRANK_SORT:
            rank_mode = RANK_MODE.CPC
        else:
            rank_mode = RANK_MODE.DEFAULT
        res["rank_mode"] = rank_mode
        if offset == 0:
            user_portrait_data = {"service_ids": tag_service_id,
                                  'doctor_ids': tag_doctor_ids,
                                  'sku_list': tag_sku_list,
                                  "rank_mode": rank_mode,
                                  "total_count": len(tag_sku_list),
                                  "highlight": []
                                  }
        else:
            user_portrait_data = {"service_ids": [],
                                  'doctor_ids': [],
                                  'sku_list': [],
                                  "rank_mode": rank_mode,
                                  "total_count": 0,
                                  "highlight": []
                                  }
        normal_sort_data = {"service_ids": service_id,
                            'doctor_ids': doctor_ids,
                            'sku_list': sku_list,
                            "rank_mode": rank_mode,
                            "total_count": len(tag_sku_list),
                            "highlight": []
                            }
        return {"user_portrait_data": user_portrait_data, "normal_sort_data": normal_sort_data}
    except:
        logging_exception()
        logger.error("catch exception,err_msg:%s" % traceback.format_exc())
        return {"user_portrait_data": {}, "normal_sort_data": {}}


@bind('doris/search/content_detail_service')
def content_detail_service(card_id=-1, card_type=None, card_author_message={}, user_city_tag_id=-1, tags={}, size=3,
                           related_serviceid=[]):
    """
    不同内容详情页向美购转化
    :param card_id:
    :param card_type:
    :param user_type:
    :param user_city_tag_id:
    :param tags:
    :param size:
    :return:
    """
    try:
        content_keyword = []
        ###先获取本卡片的内容关键词

        if card_type == CARD_TYPE.ARTICLE:
            get_card_query = {
                "query": {
                    "term": {
                        "article_id": card_id
                    }
                }
            }
        else:
            get_card_query = {
                "query": {
                    "term": {
                        "id": card_id
                    }
                }
            }

        if card_type == CARD_TYPE.USERTOPIC:
            index_es = "tractate"

        elif card_type == CARD_TYPE.DOCTORTOPIC:
            index_es = "doctortractate"
        else:
            index_es = card_type

        res = es_query(index_es, get_card_query, 0, 1)
        if res["hits"]["total"] > 0:
            for item in res["hits"]["hits"]:
                if "content_keyword" in item["_source"]:
                    content_keyword = item["_source"]["content_keyword"]

        logging.info("get content_keyword:%s" % content_keyword)
        user_id = -1
        user_type = USER_TYPE.NORMAL
        merchant_id = -1
        hospital_id = -1
        current_old_tags = []
        sun_old_tags = []
        parent_old_tags = []
        function_list = []
        service_ids = []
        sku_ids = list()
        all_tags = []
        sort_params = {}
        ##先获取该卡片的信息
        if card_author_message:
            user_id = card_author_message.get('id', None)
            user_type = card_author_message.get("type", None)
            merchant_id = card_author_message.get("merchant_id", None)
            hospital_id = card_author_message.get("hospital_id", None)

        ###
        if user_city_tag_id:
            sort_params["user_city_tag_id"] = user_city_tag_id
            sort_params["in_whitelist"] = 1

        ##获取标签信息
        if tags:
            for key, value in tags.items():
                if key == "current_tags":
                    current_old_tags = value
                if key == "sun_tags":
                    sun_old_tags = value
                if key == "parent_tags":
                    parent_old_tags = value

            all_tags.extend(current_old_tags)
            all_tags.extend(sun_old_tags)
            all_tags.extend(parent_old_tags)

        should_query = [{
            "terms": {
                "closure_tag_ids": all_tags
            }
        }
        ]

        if len(content_keyword) > 0:
            should_query.append({
                "terms": {
                    "closure_tags": content_keyword
                }
            })
        ##根据卡片所属用户的性质判断 医院
        if user_type == USER_TYPE.OFFICER:
            should_query.append({
                "term": {
                    "doctor.id": user_id
                }
            })
            should_query.append({
                "term": {
                    "doctor.hospital.id": hospital_id
                }
            })
            function_list.append({
                "filter": {
                    "term": {
                        "doctor.id": user_id
                    }
                },
                "weight": 2000
            })
            function_list.append(
                {
                    "filter": {
                        "term": {
                            "doctor.hospital.id": hospital_id
                        }
                    },
                    "weight": 10000
                })

        if len(current_old_tags) > 0:
            function_list.append({
                "filter": {
                    "terms": {
                        "closure_tag_ids": current_old_tags
                    }
                },
                "weight": 2000
            })

        if len(sun_old_tags) > 0:
            function_list.append({
                "filter": {
                    "terms": {
                        "closure_tag_ids": sun_old_tags
                    }
                },
                "weight": 500
            })

        if len(parent_old_tags) > 0:
            function_list.append({
                "filter": {
                    "terms": {
                        "closure_tag_ids": parent_old_tags
                    }
                },
                "weight": 100
            })

        if len(content_keyword) > 0:
            function_list.append({
                "filter": {
                    "terms": {
                        "closure_tags": content_keyword
                    }
                },
                "weight": 200
            })

        query = {
            "query": {
                "function_score": {
                    "functions": function_list,
                    "query": {
                        "bool": {
                            "must": process_filters(filters={}),
                            "should": should_query,
                            "minimum_should_match": 1
                        }
                    },
                    "boost_mode": "replace",
                    "score_mode": "sum",
                }
            }
        }
        if len(related_serviceid) > 0:
            query["query"]["function_score"]["query"]["bool"]["must_not"] = (
                {
                    "terms": {
                        "id": related_serviceid
                    }
                }
            )

        query["_source"] = {"include": ["id", "is_promote", "doctor", "hospital", "closure_tag_ids", "sku_list"]}

        all_datas = []
        if user_type == USER_TYPE.OFFICER or user_type == USER_TYPE.NORMAL:
            if user_type == USER_TYPE.NORMAL:
                real_size = 20
                query["sort"] = process_sorting(sort_type=SERVICE_ORDER_TYPE.DEFAULT, sort_params=sort_params,
                                                weight_service_cpc=True, weight_tag_score=True)
            else:
                real_size = size
                query["sort"] = process_sorting(sort_type=SERVICE_ORDER_TYPE.DEFAULT, sort_params=sort_params,
                                                weight_service_cpc=True, weight_office_score=True)

            logging.info("get content_detail_service query:%s" % query)

            res = es_query("service", query, 0, real_size)
            if res["hits"]["total"] > 0:
                for item in res["hits"]["hits"]:
                    service_id = item["_source"]["id"]
                    sku_id = item["_source"]["sku_list"][0]["sku_id"]
                    doctor_city_id = item["_source"]["doctor"]["hospital"]["city_tag_id"]
                    sort = item["sort"]
                    all_datas.append(
                        {"service_id": service_id, "sku_id": sku_id, "sort": sort, "doctor_city_id": doctor_city_id})

            if user_type == USER_TYPE.OFFICER:
                for item in all_datas:
                    sku_ids.append(item.get("sku_id"))
                    service_ids.append(item.get("service_id"))

                return {"sku_ids": sku_ids, "service_ids": service_ids}

            else:
                random_data = []
                if len(all_datas) > size:
                    random_data = random.sample(all_datas, size)
                else:
                    random_data = all_datas
                for item in random_data:
                    sku_ids.append(item.get("sku_id"))
                    service_ids.append(item.get("service_id"))

                return {"sku_ids": sku_ids, "service_ids": service_ids}

        else:
            query_body = ""
            for item in range(2):
                doctor_id = {"0": user_id, "1": merchant_id}

                query["query"]["function_score"]["query"]["bool"]["should"] = [
                    {
                        "terms": {
                            "closure_tag_ids": all_tags
                        }
                    },
                    {
                        "term": {
                            "doctor.id": doctor_id.get(str(item), user_id)
                        }
                    },
                    {
                        "term": {
                            "doctor.hospital.id": hospital_id
                        }
                    },
                    {
                        "terms": {
                            "closure_tags": content_keyword
                        }
                    }
                ]

                query["query"]["function_score"]["functions"] = [
                    {
                        "filter": {
                            "term": {
                                "doctor.id": doctor_id.get(str(item), user_id)
                            }
                        },
                        "weight": 2000
                    },
                    {
                        "filter": {
                            "term": {
                                "doctor.hospital.id": hospital_id
                            }
                        },
                        "weight": 10000
                    }
                ]
                query["from"] = 0
                query["size"] = 10
                query["sort"] = process_sorting(sort_type=SERVICE_ORDER_TYPE.DEFAULT, sort_params=sort_params,
                                                weight_service_cpc=True, weight_office_score=True)

                if len(function_list):
                    query["query"]["function_score"]["functions"].extend(function_list)
                query_doctor_index_name = es_index_adapt(index_prefix=settings.ES_INDEX_PREFIX, doc_type="service",
                                                         rw="read")

                logging.info("get content_detail_service query:%s" % query)
                header_dict = {'index': query_doctor_index_name, 'type': "service"}
                query_body += "{}\n{}\n".format(json.dumps(header_dict), json.dumps(query))

            res = es_msearch(query_body, es_hosts_config=settings.ES_SERVICE_HOSTS)
            tag_data = []
            have_doctor_tag_data = []
            have_doctor_data = []
            if len(res) > 0 and "responses" in res:
                for item in res["responses"]:
                    if "hits" in item and "hits" in item["hits"] and len(item["hits"]["hits"]) > 0:
                        results_list = item["hits"]["hits"]
                        for item in results_list:
                            if 'inner_hits' in item:
                                sku_id = item['inner_hits']['sku_list']['hits']['hits'][0]['_source']['sku_id']
                                service_id = item["_source"]["id"]
                                score = item["_score"]
                                if score >= 12000:
                                    have_doctor_tag_data.append(
                                        {"service_id": service_id, "sku_id": sku_id, "score": score})
                                elif score >= 10000 and score < 12000:
                                    have_doctor_data.append(
                                        {"service_id": service_id, "sku_id": sku_id, "score": score})
                                else:
                                    tag_data.append({"service_id": service_id, "sku_id": sku_id, "score": score})

            if len(have_doctor_tag_data) > 0:
                for item in have_doctor_tag_data:
                    skuid = item.get("sku_id", None)
                    serviceid = item.get("service_id", None)
                    if skuid not in sku_ids:
                        sku_ids.append(skuid)
                    if serviceid not in service_ids:
                        service_ids.append(serviceid)
                    if len(sku_ids) >= size and len(service_ids) >= size:
                        break

            if len(sku_ids) < size and len(service_ids) < size:
                for item in have_doctor_data:
                    skuid = item.get("sku_id", None)
                    serviceid = item.get("service_id", None)
                    if skuid not in sku_ids:
                        sku_ids.append(skuid)
                    if serviceid not in service_ids:
                        service_ids.append(serviceid)
                    if len(sku_ids) >= size and len(service_ids) >= size:
                        break

            if len(sku_ids) < size and len(service_ids) < size:
                if len(tag_data) > size - len(sku_ids):
                    random_data = random.sample(tag_data, size - len(sku_ids))
                else:
                    random_data = tag_data
                logging.info("get random_data:%s" % random_data)
                for item in random_data:
                    skuid = item.get("sku_id", None)
                    serviceid = item.get("service_id", None)
                    if skuid not in sku_ids:
                        sku_ids.append(skuid)
                    if serviceid not in service_ids:
                        service_ids.append(serviceid)
                    if len(sku_ids) >= size and len(service_ids) >= size:
                        break

            return {"sku_ids": sku_ids, "service_ids": service_ids}

    except:
        logging_exception()
        logger.error("catch exception,err_msg:%s" % traceback.format_exc())
        return {"sku_ids": [], "service_ids": []}
