Exemple #1
0
    def con_es(self, is_auth=False):
        """
        :param is_auth: 用户名密码状态
        :return: es_obj
        """

        # 读取mapping
        mapping_json_path = 'config/NewsESMapping.json'
        with open(os.path.join(BASE_DIR, mapping_json_path)) as f:
            mapping = json.load(f)
        try:
            if is_auth:
                es = Elasticsearch(
                    hosts=ES_HOST_PORT,  # 主机 端口
                    http_auth=('elastic', 'password'),  # 认证
                    http_compress=True  # 压缩
                )
            else:
                es = Elasticsearch(hosts=ES_HOST_PORT, http_compress=True)
        except:
            traceback.print_exc()
            globalLog.error(traceback.format_exc())
        else:
            self.es = es
            # 创建索引 忽视创建重复400状态码
            es.indices.create(index=ES_INDEX, body=mapping, ignore=[400])
            return es
Exemple #2
0
def callback(channel, method, properties, message):
    try:
        print('[*] Waiting for logs. To exit press CTRL+C')
        msg = pickle.loads(message)
        print("消息内容:{}".format(msg))
        return Processing(msg).process_data(channel, method)
    except:
        traceback.print_exc()
        globalLog.error(traceback.format_exc())
        channel.basic_nack(delivery_tag=method.delivery_tag, requeue=True)
        channel.close(reply_text='callback func running Error')
Exemple #3
0
    def exchange_aliases(self, index_name, alias_name):
        """
        为特定索引创建别名

        :param index_name: 索引名
        :param alias_name: 别名
        """
        if self.es:
            self.es.indices.put_alias(index=[index_name], name=alias_name)
        else:
            globalLog.error(traceback.format_exc())
            raise Exception('not es object')
Exemple #4
0
def con_redis():
    # decode_responses 将返回数据不是二级制byte
    redis_cli = redis.StrictRedis(host=REDIS_HOST,
                                  port=REDIS_PORT,
                                  db=REDIS_DB,
                                  password=REDIS_PASSWORD)
    try:
        redis_cli.ping()
    except:
        traceback.print_exc()
        globalLog.error(traceback.format_exc())
    else:
        return redis_cli
Exemple #5
0
def con_mongo(collection_name=None):
    """
    :param collection_name: mongo集合名
    :return: mongo游标
    """
    try:
        mg_cli = pymongo.MongoClient(MONGO_URL)
        mg_db = mg_cli[MONGO_DB]
        mg_cursor = mg_db[collection_name]
    except:
        traceback.print_exc()
        globalLog.error(traceback.format_exc())
    else:
        return mg_cursor
    def process_data(self, channel=None, method=None):
        """
        采用多线程分布式数据处理 => callback

        主线程: 限时/主动发送心跳操作
        子线程: 处理数据方法

        :param channel: 信道
        :param method: mq方法
        """

        thread_process = MyThread(self.thread_process_data,
                                  args=(channel, method))
        thread_process.setDaemon(True)
        thread_process.start()

        # 限制任务时间10分钟 超过就把次消息拒绝
        for i in range(1, 61 * 10):
            time.sleep(1)
            result = thread_process.get_result()

            # 每10s消费者主动发送一次心跳检测
            if i % 30 == 0:
                # 将确保处理数据方法完整执行完成
                # 防止server端主动提出分手 => 认为消费者死掉
                channel.connection.process_data_events()
            # 子线程任务处理完 => true
            if result is True:
                # 记录完成消息数据内容
                globalLog.success("消息内容:{}  消息处理总量:{}条".format(
                    self.msg, self.mongo_count))
                return result
            # 子线程任务报错 => error 或者 thread_process_data 返回 False
            elif result == 'ERROR':
                globalLog.error("处理报错消息内容:{}  消息处理总量:{}条".format(
                    self.msg, self.mongo_count))
                return 'ERROR'
            elif result is False:
                globalLog.error("处理报错消息内容:{}  消息处理总量:{}条".format(
                    self.msg, self.mongo_count))
                return False

        else:
            globalLog.warning("处理超时消息内容:{}  消息处理总量:{}条".format(
                self.msg, self.mongo_count))
            # 拒绝此条消息 放入死信队列
            channel.basic_nack(delivery_tag=method.delivery_tag, requeue=False)
Exemple #7
0
    def listening(self, queue_name='default_queue', exchange_name='default_exchange',
                  routing_key='default_route', callback=None):
        """
        监听队列里的消息, 优先启动
        """
        # 创建exchange并设置类型
        self.channel.exchange_declare(
            exchange=exchange_name,
            exchange_type='direct',
            durable=True
        )
        print("消费者连接MQ成功")

        # 指定死信队列配置 创建死信队列脚本 path: mq/DLXQueueScript.py
        arguments = {"x-dead-letter-exchange": "dlx.financial_news", "x-dead-letter-routing-key": "dlx"}
        # durable 持久化
        # auto_delete 是否自动删除queue 当还一个消费者断开连接
        # 切换到指定的队列中,如果队列不存在,则创建
        self.channel.queue_declare(
            queue=queue_name, durable=True, exclusive=False, auto_delete=False, arguments=arguments
        )
        # 绑定交换器和队列
        self.channel.queue_bind(
            exchange=exchange_name,
            routing_key=routing_key,
            queue=queue_name
        )

        # 在处理并确认上一条消息之前,不要将新消息发送给消费者
        # 而是将其分派给不忙的下一个工作程序 防止消息积压
        self.channel.basic_qos(prefetch_count=1) # Queue每次给每个消费者发送一条消息

        if not callback:
            callback = self.__callback

        # 调用回调函数处理消息数据
        # no_ack=False 设置为消息处理完毕后,消费者必须明确告知rabbitMQ server已经处理完毕
        # 否则rabbitMQ server将视为消息处理失败,把该消息重新放回到队列当中
        self.channel.basic_consume(queue='financial_news', on_message_callback=callback, auto_ack=False)
        try:
            # 消费者阻塞监听
            self.channel.start_consuming()
        except:
            traceback.print_exc()
            globalLog.error(traceback.format_exc())
Exemple #8
0
def con_mysql(sql, con):
    """
    通过sqlalchemy连接数据库
    :param sql: sql查询语句
    :param con: mysql_url 连接地址 ==>str
    :return: 数据
    """
    try:
        conn = create_engine(con)
        cursor = conn.execute(sql)
        result = cursor.fetchall()
    except:
        traceback.print_exc()
        globalLog.error(traceback.format_exc())
    else:
        # 查询数据长度1时直接从列表中获取元组中获取数据
        # 例: [(423507,)]
        if len(result) == 1:
            return result[0][0]
        else:
            return result
    def thread_process_data(self, channel=None, method=None):
        """
        子线程执行处理数据任务
        :param channel: 信道
        :param method: mq方法 可以获取任务id
        :return: 是否执行ok
        """
        try:
            # 处理数据量
            data = self.get_mongo()

            # 检测模型是否开启
            if self.mt_model is False:
                # 拒绝传入的消息。此方法允许客户端拒绝消息
                # 如果requeue为true,则服务器将尝试重新排队该消息。
                # 如果requeue为false或requeue尝试失败,则消息将被丢弃或置为死信。
                channel.basic_reject(delivery_tag=method.delivery_tag,
                                     requeue=True)
                globalLog.error('算法模型服务端口未开启')
                print('算法模型服务端口未开启, 消息以重新队列消息')
                return 'ERROR'

            # 通过缓存获取抓撞库数据
            data_df = self.redis_cache()

            es_actions = []
            sql_actions = []
            for n, mongo_data in enumerate(data, start=1):
                contents = ''.join(mongo_data.get('contents'))  # 数据处理的内容
                # 1. 调用模型提取公司名称 ==> list
                cnm = GetCompanyNameModel()
                # # TODO 旧模型
                # client1_list = cnm.get_api(text=contents, client_num=cnm.bclient_1)
                # client2_list = cnm.get_api(text=contents, client_num=cnm.bclient_2)
                # model_company_list = client1_list + client2_list
                # TODO 新模型  需要将全角转成半角
                model_company_list = cnm.get_api(text=contents,
                                                 client_num=cnm.bclient_3)
                # 2. 调用撞库 ==> list
                hit_company_list = self.hit_db(db_data=data_df, text=contents)
                # 3. 拼接两个方法返回值 ==> list
                company_list = list(set(model_company_list + hit_company_list))

                # TODO 模型调用获取APP并找到公司名称
                # TODO 所有公司名称需要过滤别名库获取公司全称

                # 拼装数据 ES Mysql
                action_data, sql_data = self.format_data(
                    mongo_data, company_list)
                es_actions.append(action_data)
                sql_actions.append(sql_data)

            # 保存数据库
            self.save_sql(sql_actions)  # [Mysql]
            self.save_es(es_actions)  # [ES]
        except:
            # 数据处理报错记录并返回error
            traceback.print_exc()
            globalLog.error(traceback.format_exc())
            return 'ERROR'
        else:
            return True