docstr: step 1, 用AC自动机检测出匹配到的用户词
  step 2, 每个用户词查找最小分词边界，计算每种分词结果的打分，PK
  step 3, 怎么处理冲突？
    3.a. 假设 AC自动机检测到的关键词都是顺序的，那么只需要考虑前后两个的替换词即可
    3.b. 假如前后两个替换词没有位置冲突，那么直接把前一个加到替换列表里
    3.c. 假如前后两个替换词有冲突，比较分数，舍弃一个，更新上一个替换的位置
  step 4, 最终依次执行替换
docstr_tok: ["step","1",",","\u7528AC\u81ea\u52a8\u673a\u68c0\u6d4b\u51fa\u5339\u914d\u5230\u7684\u7528\u6237\u8bcd","step","2",",","\u6bcf\u4e2a\u7528\u6237\u8bcd\u67e5\u627e\u6700\u5c0f\u5206\u8bcd\u8fb9\u754c\uff0c\u8ba1\u7b97\u6bcf\u79cd\u5206\u8bcd\u7ed3\u679c\u7684\u6253\u5206\uff0cPK","step","3",",","\u600e\u4e48\u5904\u7406\u51b2\u7a81\uff1f","3.a",".","\u5047\u8bbe","AC\u81ea\u52a8\u673a\u68c0\u6d4b\u5230\u7684\u5173\u952e\u8bcd\u90fd\u662f\u987a\u5e8f\u7684\uff0c\u90a3\u4e48\u53ea\u9700\u8981\u8003\u8651\u524d\u540e\u4e24\u4e2a\u7684\u66ff\u6362\u8bcd\u5373\u53ef","3.b",".","\u5047\u5982\u524d\u540e\u4e24\u4e2a\u66ff\u6362\u8bcd\u6ca1\u6709\u4f4d\u7f6e\u51b2\u7a81\uff0c\u90a3\u4e48\u76f4\u63a5\u628a\u524d\u4e00\u4e2a\u52a0\u5230\u66ff\u6362\u5217\u8868\u91cc","3.c",".","\u5047\u5982\u524d\u540e\u4e24\u4e2a\u66ff\u6362\u8bcd\u6709\u51b2\u7a81\uff0c\u6bd4\u8f83\u5206\u6570\uff0c\u820d\u5f03\u4e00\u4e2a\uff0c\u66f4\u65b0\u4e0a\u4e00\u4e2a\u66ff\u6362\u7684\u4f4d\u7f6e","step","4",",","\u6700\u7ec8\u4f9d\u6b21\u6267\u884c\u66ff\u6362"]
code: def run(self, query):
      """
      step 1, 用AC自动机检测出匹配到的用户词
      step 2, 每个用户词查找最小分词边界，计算每种分词结果的打分，PK
      step 3, 怎么处理冲突？
        3.a. 假设 AC自动机检测到的关键词都是顺序的，那么只需要考虑前后两个的替换词即可
        3.b. 假如前后两个替换词没有位置冲突，那么直接把前一个加到替换列表里
        3.c. 假如前后两个替换词有冲突，比较分数，舍弃一个，更新上一个替换的位置
      step 4, 最终依次执行替换
      """
      last_bound = None
      last_phrase_list = None
      last_lm_score = None
      all_result = []
      old_lm_score = self.calc_lm_score(query.lac_query_list)
  
      for match_info in self.user_dict.iter(query.ori_query_str):
          # print "matched: \"%s\" in query: \"%s\"" % (match_info[1][0], query.seg_query_str)
          bound = self.find_min_bound(match_info, query)
          new_lm_score, new_phrase_list = self.get_new_phrase_list(
              match_info, bound, query
          )
  
          # 如果打分比原 LAC 结果低，抛弃用户词典里的结果
          if new_lm_score <= old_lm_score:
              # print >> sys.stderr, "skipped %s, old_lm_score: %.5f, " \
              #        "new_lm_score: %.5f" % (" ".join(new_phrase_list), old_lm_score, new_lm_score)
              continue
          # 遇到的第一个匹配到的结果
          if last_bound is None:
              last_bound = bound
              last_phrase_list = new_phrase_list
              last_lm_score = new_lm_score
              continue
          if bound.left_bound > last_bound.right_bound:
              # 位置上没有冲突，则把上次的结果加到最终结果中去
              all_result.append((last_bound, last_phrase_list))
              last_bound = bound
              last_phrase_list = new_phrase_list
              last_lm_score = new_lm_score
          else:
              # 位置上有冲突
              if new_lm_score > last_lm_score:
                  # 若分数高于上次结果，则覆盖；否则丢弃
                  last_bound = bound
                  last_phrase_list = new_phrase_list
                  last_lm_score = new_lm_score
  
      if last_bound is not None:
          all_result.append((last_bound, last_phrase_list))
  
      # 合并所有替换的结果
      final_phrase_list = []
      last_index = -1
      for bound, phrase_list in all_result:
          final_phrase_list += (
              query.lac_query_list[last_index + 1 : bound.left_bound]
              + phrase_list
          )
          last_index = bound.right_bound
      final_phrase_list += query.lac_query_list[last_index + 1 :]
  
      final_result = {"word": [], "tag": []}
      for phrase in final_phrase_list:
          index = phrase.rfind("/")
          word = phrase[0:index]
          tag = phrase[index + 1 :]
          final_result["word"].append(word)
          final_result["tag"].append(tag)
  
      return final_result
  
imports: import io
  import numpy
  import six
label_desc: Use image node_id 7 for calling the Interventer obj's underlying member method code with example usage: obj.run(query) and returns: final_result