ソースを参照

公告分类规则优化调整

znj 4 ヶ月 前
コミット
3af454c6a6

+ 22 - 2
BiddingKG/dl/channel/channel_bert.py

@@ -417,6 +417,8 @@ def channel_predict(title,text):
     # process text
     if title in text:
         text = text.replace(title, '', 1)
+        text = text.lstrip(",")
+        text = text.lstrip("。")
     if "##attachment##" in text:
         main_text,attachment_text = text.split("##attachment##",maxsplit=1)
         # print('main_text',main_text)
@@ -527,8 +529,25 @@ def merge_channel(list_articles,channel_dic,original_docchannel):
             elif docchannel=='公告变更' and pred_channel in ['中标信息','废标公告','候选人公示','合同公告']:
                 channel_dic['docchannel']['docchannel'] = pred_channel
                 channel_dic['docchannel']['use_original_docchannel'] = 0
+            elif docchannel in ['中标信息','候选人公示'] and pred_channel in ['中标信息','候选人公示']:
+                if re.search('候选人(变更)?公[告示]|评标(结果)?(公[告示]|报告)|评审结果', title):
+                    channel_dic['docchannel']['docchannel'] = '候选人公示'
+                    channel_dic['docchannel']['use_original_docchannel'] = 0
+                else:
+                    if original_docchannel in [101,119]:
+                        channel_dic['docchannel']['docchannel'] = class_dict.get(original_docchannel, '原始类别')
+                        channel_dic['docchannel']['use_original_docchannel'] = 1
+                    else:
+                        channel_dic['docchannel']['docchannel'] = pred_channel
+                        channel_dic['docchannel']['use_original_docchannel'] = 0
+            elif docchannel in ['中标信息','候选人公示'] and pred_channel=='开标记录':
+                re_text_len = max(500,len(text)//3)
+                re_text = text[:re_text_len]
+                if re.search('开标记录|截标信息|开标安排|开标数据表|开标信息|开标情况|开标一览表|开标结果',re_text):
+                    channel_dic['docchannel']['docchannel'] = '开标记录'
+                    channel_dic['docchannel']['use_original_docchannel'] = 0
 
-            else:
+            if 'use_original_docchannel' not in channel_dic['docchannel']:
                 original_type = class_dict.get(original_docchannel, '原始类别')
                 if pred_channel in tenderee_type and docchannel in tenderee_type and original_type not in tenderee_type:
                     # pred_channel和docchannel都是同一(招标/中标)类型时,original_docchannel不一致时不使用原网类型
@@ -576,7 +595,8 @@ def merge_channel(list_articles,channel_dic,original_docchannel):
         else:
             main_text = text
         main_text = text_process(main_text)
-        if re.search("采购实施月份|采购月份|预计(招标|采购|发标|发包)(时间|月份)|招标公告预计发布时间",main_text[:len(main_text)//2]):
+        # if re.search("采购实施月份|采购月份|预计(招标|采购|发标|发包)(时间|月份)|招标公告预计发布时间",main_text[:max(500,len(main_text)//2)]):
+        if re.search("采购实施月份|采购月份|预计(招标|采购|发标|发包)(时间|月份)|招标公告预计发布时间",main_text):
             front_text_len = len(main_text) // 3 if len(main_text) > 300 else 100
             front_text = main_text[:front_text_len]
             if re.search("意向|意愿",title) or re.search("意向|意愿",front_text):

+ 1 - 0
BiddingKG/dl/interface/extract.py

@@ -276,6 +276,7 @@ def predict(doc_id,text,title="",page_time="",web_source_no='',web_source_name="
     if sentence2_list_attach!=[] and requirement_text == '' and aptitude_text == '' and addr_bidopen_text=="":
         parse_document = ParseDocument(text, True, list_obj=sentence2_list_attach)
         requirement_text, aptitude_text, addr_bidopen_text, addr_bidsend_text, out_lines, requirement_scope, pinmu_name, list_policy = extract_parameters(parse_document)
+    # print('out_lines',out_lines)
     # if addr_bidopen_text == '':
     #     addr_bidopen_text = extract_addr(list_articles[0].content)
     addr_dic, time_dic, code_investment = predictor.getPredictor('entity_type_rule').predict(list_entitys, list_sentences, list_articles)

+ 45 - 18
BiddingKG/dl/interface/predictor.py

@@ -4128,16 +4128,20 @@ class DocChannel():
   def load_pattern(self):
       self.type_dic = {
           '土地矿产': '供地结果|(土地|用地|宗地|地块|海域|矿)的?(基本信息|基本情况|概况|信息|详情|来源|用途|性质|编号|位置|坐落|使用年限|出让年限)|(土地|山地|农田)(经营权)?(出让|出租|招租|租赁|承包|流转)|流转土地',
-          '拍卖出让': '(拍卖|变卖|流拍|竞拍)的?(公告|活动|信息|结果|成交|主体|标的|资产|财产|方式|类型|流程|程序|规则|价格|保证金|时间)|(公开|进行|密封)(拍卖|变卖|竞拍)|第[一二三]次拍卖|(资产|司法|网络)拍卖|交易方式.{,2}拍卖|拍卖会',
-          '产权交易': '(产权|资产|权证)的?(类型|类别|用途|性质|状态|信息|名称|编号|(基本)?情况)|(经营权|承包权|使用权|租赁权|股权|债权|排污权|化学需氧量|储备量)(挂牌|转让|出让)|竞价销售|销售结果|房屋所有权房产|免租期限|交易期限|(受让|转让|承租|出租)(人|方)|(店面|店铺|商铺|铺位?|门面|门市|食堂|饭堂|校舍|车位|停车场|厂?房|仓?库|馆|资产|物业|房产|房屋|场地|农田|鱼?塘)\w{,4}(处置|招租|出租|续租|租赁|转让)|(出租|转让|产权|资产)(项目|中标|成交|流标|废标)|出租(用途|类型)|转让底价|租赁(标的物|情况)|看[样货](时间|地[点址]|方式|仓库|验货)|最小加价|加价[幅梯]度|交易模式[::\s]*延时竞价销售|挂牌(开始|结束)时间',
+          '拍卖出让': '(拍卖|变卖|流拍|竞拍|竞买)的?(公告|活动|信息|结果|成交|主体|标的|资产|财产|方式|类型|流程|程序|规则|价格|保证金|时间)|(公开|进行|密封)(拍卖|变卖|竞拍)|第[一二三四五六七八九\d]次拍卖|(资产|司法|网络)拍卖|交易方式.{,2}拍卖|拍卖会|(拍卖.?方式|起拍价)[::]|竞买人资格|竞买人资质要求',
+          '产权交易': '(产权|资产|权证)的?(类型|类别|用途|性质|状态|信息|名称|编号|(基本)?情况)|(经营权|承包权|使用权|租赁权|股权|债权|排污权|化学需氧量|储备量)(挂牌|转让|出让)|竞价销售|销售结果|房屋所有权房产|免租期限|交易期限|(受让|转让|承租|出租)(人|方)|(店面|店铺|商铺|铺位?|门面|门市|食堂|饭堂|校舍|车位|停车场|厂?房|仓?库|馆|资产|物业|房产|房屋|场地|农田|鱼?塘)\w{,4}(处置|招租|出租|续租|租赁|转让)|(出租|转让|产权|资产)(项目|中标|成交|流标|废标)|出租(用途|类型)|转让底价|租赁(标的物|情况)|看[样货](时间|地[点址]|方式|仓库|验货)|最小加价|加价[幅梯]度|交易模式[::\s]*延时竞价销售|挂牌(开始|结束)时间|挂牌价格?',
           '采招数据': '(采购|招标)(条件|范围|文件|内容)|(申请人|投标人|供应商|报价人|参选人)的?资格要求;|采购需求清单|最低价排序|竞争性采购方式|采购进行公开竞价|竞价模式[::\s]*一次报价|预算金额|代理银行资格选定'  # |变更|答疑|澄清|中标|成交|合同|废标|流标 |(采购|招标|代理)(人|机构|单位)|
       }
 
-      self.title_type_dic = {
-          '土地矿产': '(土地|用地|宗地|荒地|山地|海域|矿)(出让|出租|招租|租赁|承包|流转|使用权|经营权|征收|划拨|中标|成交)|供地结果|矿业权|探矿权|采矿权|(土地|用地|宗地|地块)(使用权)?(终止|中止|网上)?(挂牌|出让|拍卖|招拍|划拨)|征收土地',
-          '拍卖出让': '(拍卖|变卖|流拍|竞拍)的?(公告|公示)|拍卖|变卖|流拍|竞拍',
-          '产权交易': '经营权|承包权|使用权|租赁权|股权|债权|排污权|化学需氧量|储备量|竞价销售|销售结果|出租|招租|拍租|竞租|续租|挂牌|出让',
-          '采招数据': '(采购|招标|询价|议价|比价|比选|遴选|邀请|邀标|磋商|洽谈|约谈|谈判|征询|调研)的?(公告|公示|中标|成交|结果|$)|工程招标|定点服务|(设备|服务|\w{2})[直采]购|(建设|改造)项目|工程|拦标价|控制价|银行|资格选定|资金|公款|存款|存放|现金管理|招募|入围|入库',
+      self.title_type_dic = { # ‘**2’ 为类别强相关关键词,不会被其他规则修正
+          '土地矿产': '(土地|用地|宗地|荒地|山地|海域|矿)(出让|出租|招租|租赁|承包|流转|使用权|经营权|征收|划拨|中标|成交)|供地结果|矿业权|探矿权|采矿权|(土地|用地|宗地|地块)(使用权)?(终止|中止|网上)?(挂牌|出让|拍卖|招拍|划拨)|征收土地|流转土地',
+          '土地矿产2': '(土地|用地|宗地|荒地|山地|海域|矿)(出让|出租|招租|租赁|承包|流转|使用权|经营权|征收|划拨|中标|成交)|供地结果|矿业权|探矿权|采矿权|(土地|用地|宗地|地块)(使用权)?(终止|中止|网上)?(挂牌|出让|拍卖|招拍|划拨)|征收土地|流转土地',
+          '拍卖出让': '(拍卖|变卖|拍(变)卖|流拍|竞拍|竞买)[\)\])】]?的?(公告|公示|预告|告知书)|拍卖|变卖|流拍|竞拍|第[一二三四五六七八九\d]次拍卖|拍卖会$',
+          '拍卖出让2': '(拍卖|变卖|拍(变)卖|流拍|竞拍|竞买)[\)\])】]?的?(公告|公示|预告|告知书)|拍卖|变卖|流拍|第[一二三四五六七八九\d]次拍卖|拍卖会$',
+          '产权交易': '经营权|承包权|使用权|租赁权|股权|债权|排污权|化学需氧量|储备量|竞价销售|销售结果|出租|招租|拍租|竞租|续租|挂牌|出让|废[旧弃]?(物资|设备|资源|金属|钢筋|料)处[置理]',
+          '产权交易2': '使用权|租赁权|股权|债权|排污权|竞价销售|销售结果|出租|招租|拍租|竞租|续租|挂牌|出让|废[旧弃]?(物资|设备|资源|金属|钢筋|料)处[置理]',
+          # '采招数据': '(采购|招标|询价|议价|比价|比选|遴选|邀请|邀标|磋商|洽谈|约谈|谈判|征询|调研)的?(公告|公示|中标|成交|结果|$)|工程招标|定点服务|(设备|服务|\w{2})[直采]购|(建设|改造)项目|工程|拦标价|控制价|银行|资格选定|资金|公款|存款|存放|现金管理|招募|入围|入库',
+          '采招数据': '(采购|招标|询价|议价|比价|比选|遴选|邀请|邀标|磋商|洽谈|约谈|谈判|征询|调研)的?(公告|公示|中标|成交|结果|$)|工程招标|定点服务|(设备|服务|\w{2})[直采]购|(建设|改造)项目|拦标价|控制价|资格选定|资金|公款|存款|现金管理|招募|入库',
           # |竞价 采招/产权都有竞价方式 # 意向|需求|预公?告|报建|总承包|工程|施工|设计|勘察|代理|监理 |变更|答疑|澄清|中标|成交|合同|废标|流标
           '新闻资讯': '(考试|面试|笔试)成绩|成绩的?(公告|公示|公布)|公开招聘|招聘(公告|简章|启事|合同制)|疫情防控\s{,5}(通知|情况|提示)|行政审批结果'
       }
@@ -4173,7 +4177,7 @@ class DocChannel():
           '中标信息': '(中标|中选|中价|中租|成交)?|入选|确认)(候选人|人|供应商|记录|结果|变更|情况)?的?(公告|公示|结果)|未?入围(公示|公告)|(遴选|采购|招标|竞价|议价|比选|询比?价|评选|谈判|邀标|邀请|洽谈|约谈|评标|发包|磋商|交易|出让|抽取|抽签)\w{,2}结果|单一来源(采购|招标)?的?(中标|成交|结果)|中标通知书|中标$|项目中标|(项目|工程|服务|定点)的?结果公[告示]|超市直购订单', # |开标(记录|信息|情况)
           '资审结果': '((资格|资质)(审查|预审|后审|审核)|资审)结果(公告|公示)?|(资质|资格)(预审|后审)公示|资审及业绩公示',
           '招标公告': '(采购|招标|询价|议价|竞价|比价|比选|遴选|邀请|邀标|磋商|洽谈|约谈|谈判|拍卖|招租|交易|出让)的?(公告|公示|$)|公开(采购|招标|招租|拍卖|挂牌|出让)|(资审|预审|后审)公告',
-          '开标记录': '开标记录|截标信息|评委名单公示|开标安排|开标数据表|开标信息|开标情况|开标一览表|开标结果|开标会',
+          '开标记录': '开标记录|截标信息|评委名单公示|开标安排|开标数据表|开标信息|开标情况|开标一览表|开标结果|开标会|评审专家公示',
           '验收合同': '(验收|履约)(公告|公示)|(验收|履约)(结果|报告|意见|单)(公告|公示)|预留项目执行情况'
       }
 
@@ -4458,23 +4462,29 @@ class DocChannel():
       def get_type(title, text):
           if re.search(self.title_type_dic['土地矿产'], title) or re.search(self.type_dic['土地矿产'],
                                                                    text):  # and re.search('(土地|用地|宗地|地块)(经营权)?(流转|承包|出租|招租|租赁|确权)', text)==None
-              if re.search(self.title_type_dic['采招数据'], text.strip().split(' ')[0] + title):
+              if re.search(self.title_type_dic['采招数据'], text.strip().split(' ')[0] + title) \
+                  and not re.search(self.title_type_dic['土地矿产2'], title):
                   return '采招数据', re.search(self.title_type_dic['采招数据'], text.strip().split(' ')[0] + title).group(0)
               return '土地矿产', (re.search(self.title_type_dic['土地矿产'], title) or re.search(self.type_dic['土地矿产'], text)).group(0)
-          elif re.search(self.title_type_dic['产权交易'], title) or re.search(self.type_dic['产权交易'], text):
-              if re.search(self.title_type_dic['采招数据'], text.strip().split(' ')[0] + title):
-                  return '采招数据', re.search(self.title_type_dic['采招数据'], text.strip().split(' ')[0] + title).group(0)
-              return '产权交易', (re.search(self.title_type_dic['产权交易'], title) or re.search(self.type_dic['产权交易'], text)).group(0)
+
           elif (re.search(self.title_type_dic['拍卖出让'], title) or re.search(self.type_dic['拍卖出让'], text)):
-              if re.search(self.title_type_dic['采招数据'], text.strip().split(' ')[0] + title):
+              if re.search(self.title_type_dic['采招数据'], text.strip().split(' ')[0] + title) \
+                  and not re.search(self.title_type_dic['拍卖出让2'], title):
                   return '采招数据', re.search(self.title_type_dic['采招数据'], text.strip().split(' ')[0] + title).group(0)
               return '拍卖出让', (re.search(self.title_type_dic['拍卖出让'], title) or re.search(self.type_dic['拍卖出让'], text)).group(0)
+
+          elif re.search(self.title_type_dic['产权交易'], title) or re.search(self.type_dic['产权交易'], text):
+              if re.search(self.title_type_dic['采招数据'], text.strip().split(' ')[0] + title) \
+                  and not re.search(self.title_type_dic['产权交易2'], title):
+                  return '采招数据', re.search(self.title_type_dic['采招数据'], text.strip().split(' ')[0] + title).group(0)
+              return '产权交易', (re.search(self.title_type_dic['产权交易'], title) or re.search(self.type_dic['产权交易'], text)).group(0)
+
           elif re.search(self.title_type_dic['采招数据'], title) or re.search(self.type_dic['采招数据'], title + text):
               return '采招数据', (
                           re.search(self.title_type_dic['采招数据'], title) or re.search(self.type_dic['采招数据'], title + text)).group(
                   0)
           elif re.search(self.title_type_dic['新闻资讯'], title):
-              if re.search(self.title_type_dic['采招数据'], title +text.strip().split(' ')[0]):
+              if re.search(self.title_type_dic['采招数据'], title +text.strip().split(' ')[0]) or re.search("银行|资格选定|资金|公款|存款|存放|现金管理|招募|入围|入库", title +text.strip().split(' ')[0]):
                   return '采招数据', re.search(self.title_type_dic['采招数据'], title +text.strip().split(' ')[0]).group(0)
               return '新闻资讯', re.search(self.title_type_dic['新闻资讯'], title).group(0)
           else:
@@ -4695,6 +4705,7 @@ class DocChannel():
       result = {'docchannel': {'docchannel': '', 'doctype': ''}}
 
       doc_type, type_kw = get_type(title, text)
+      # print(doc_type, type_kw)
       # doc_life, life_kw = get_life(title, text, prem_json, bidway, original_docchannel)
       doc_life, life_kw = get_life(title, text)
       if doc_type in self.title_type_dic:
@@ -4761,9 +4772,22 @@ class DocChannel():
           else:
               return False
 
+      tenderee = ""
+      try:
+          for k, v in prem['prem'].items():
+              for link in v['roleList']:
+                  if link['role_name'] == 'tenderee' and tenderee == "":
+                      tenderee = link['role_text']
+      except Exception as e:
+          # print('解析prem 获取招标人、代理人出错')
+          pass
       origin_dic = self.origin_dic
       title = self.title
       text = self.text
+      # 剔除招标单位名称影响
+      if tenderee:
+          title = title.replace(tenderee, " ")
+          text = text.replace(tenderee, " ")
       prem_json = json.dumps(prem, ensure_ascii=False)
       if result['docchannel']['docchannel'] in ['中标信息', '合同公告'] and origin_dic.get(
               original_docchannel, '') in ['招标公告', '采购意向', '招标预告', '公告变更'] and is_contain_winner(
@@ -4802,7 +4826,7 @@ class DocChannel():
           result['docchannel']['docchannel'] = origin_dic.get(original_docchannel, '')
           msc += '最终规则修改:预测及原始均在答疑、变更,返回原始类别'
       elif result['docchannel']['doctype'] == '采招数据' and origin_dic.get(
-              original_docchannel, '') in ['产权交易', '土地矿产'] and re.search('产权|转让|受让|招租|出租|承租|竞价|资产', text):
+              original_docchannel, '') in ['产权交易', '土地矿产'] and re.search('产权|转让|受让|招租|出租|承租|竞价', text):
           result['docchannel']['doctype'] = origin_dic.get(original_docchannel, '')
           msc += '最终规则修改:预测为采招数据,原始为产权且有关键词,返回原始类别'
       elif result['docchannel']['docchannel'] == '废标公告' and origin_dic.get(
@@ -4819,8 +4843,11 @@ class DocChannel():
           result['docchannel']['docchannel'] = '中标信息'
       if result['docchannel']['doctype'] in ['产权交易', '土地矿产', '拍卖出让'] and origin_dic.get(
               original_docchannel, '') not in ['产权交易', '土地矿产', '拍卖出让'] \
-              and (re.search(self.title_type_dic['采招数据'], title) or re.search('工程|服务|采购|询价|磋商', title) or re.search(
-          '(采购|招投?标|投标)(信息|内容|项目|公告|数量|人|单位|方式)|(建设|工程|服务|施工|监理|勘察|设计)项目|(%s)' % self.type_dic['采招数据'], text)):
+              and (re.search(self.title_type_dic['采招数据'], title) or re.search('采购|询价|磋商', title)
+               or re.search('(采购|招投?标|投标)(信息|内容|项目|公告|数量|人|单位|方式)|(建设|工程|服务|施工|监理|勘察|设计)项目|(%s)'
+          % self.type_dic['采招数据'], text)
+      ):
+          # print('test',re.findall('(采购|招投?标|投标)(信息|内容|项目|公告|数量|人|单位|方式)|(建设|工程|服务|施工|监理|勘察|设计)项目|(%s)' % self.type_dic['采招数据'], text))
           result['docchannel']['doctype'] = '采招数据'
           msc += ' 最终规则修改:预测为非采招数据,原始为采招数据且有招标关键词,返回采招数据'
       elif result['docchannel']['doctype'] in ['土地矿产'] and origin_dic.get(original_docchannel, '') in ['拍卖出让', '产权交易']: