//  [python]
def build_model(self):
    item_emb_w = tf.get_variable(
        "item_emb_w",
        [self.config['item_count'], self.config['embedding_size']])
    short_w = tf.get_variable(
        "short_w",
        [self.config['item_count'], self.config['embedding_size']])
    long_w = tf.get_variable(
        "long_w",
        [self.config['user_count'], self.config['embedding_size']])
    D = [1.0 / (x+1) for x in range(self.config['k'])]
    D.reverse()
    D = tf.convert_to_tensor(D)
    D = tf.tile(tf.expand_dims(D, -1), [1, self.config['embedding_size']])

    is_emb = tf.nn.embedding_lookup(short_w, self.s)
    hi_emb = tf.nn.embedding_lookup(item_emb_w, self.i)
    hj_emb = tf.nn.embedding_lookup(item_emb_w, self.j)
    u_emb = tf.nn.embedding_lookup(long_w, self.u)

    s_emb = tf.reduce_sum(tf.multiply(is_emb, D), 1)
    p = u_emb + tf.multiply(self.config['alpha'], s_emb) 

    self.r_i = tf.reduce_sum(tf.multiply(p, hi_emb), 1)
    self.r_j = tf.reduce_sum(tf.multiply(p, hj_emb), 1)

    self.x = self.r_i - self.r_j

    # ============== Eval ===============
    all_emb = item_emb_w
    self.eval_logits = tf.matmul(p, all_emb, transpose_b=True)
    self.i64 = tf.cast(self.i, tf.int64)
    with tf.variable_scope("metric"):
      # precision_at_k
      self.prec_1, self.prec_update_1 = tf.metrics.precision_at_k(labels=self.i64, predictions=self.eval_logits, k=1)
      self.prec_10, self.prec_update_10 = tf.metrics.precision_at_k(labels=self.i64, predictions=self.eval_logits, k=10)
      self.prec_20, self.prec_update_20 = tf.metrics.precision_at_k(labels=self.i64, predictions=self.eval_logits, k=20)
      self.prec_30, self.prec_update_30 = tf.metrics.precision_at_k(labels=self.i64, predictions=self.eval_logits, k=30)
      self.prec_40, self.prec_update_40 = tf.metrics.precision_at_k(labels=self.i64, predictions=self.eval_logits, k=40)
      self.prec_50, self.prec_update_50 = tf.metrics.precision_at_k(labels=self.i64, predictions=self.eval_logits, k=50)
      # recall_at_k
      self.recall_1, self.recall_update_1 = tf.metrics.recall_at_k(labels=self.i64, predictions=self.eval_logits, k=1)
      self.recall_10, self.recall_update_10 = tf.metrics.recall_at_k(labels=self.i64, predictions=self.eval_logits, k=10)
      self.recall_20, self.recall_update_20 = tf.metrics.recall_at_k(labels=self.i64, predictions=self.eval_logits, k=20)
      self.recall_30, self.recall_update_30 = tf.metrics.recall_at_k(labels=self.i64, predictions=self.eval_logits, k=30)
      self.recall_40, self.recall_update_40 = tf.metrics.recall_at_k(labels=self.i64, predictions=self.eval_logits, k=40)
      self.recall_50, self.recall_update_50 = tf.metrics.recall_at_k(labels=self.i64, predictions=self.eval_logits, k=50)

    # Step variable
    self.global_step = tf.Variable(0, trainable=False, name='global_step')
    self.global_epoch_step = \
        tf.Variable(0, trainable=False, name='global_epoch_step')
    self.global_epoch_step_op = \
        tf.assign(self.global_epoch_step, self.global_epoch_step+1)

    # Loss
    l2_norm = tf.add_n([
        tf.nn.l2_loss(u_emb),
        tf.nn.l2_loss(is_emb),
        tf.nn.l2_loss(hi_emb),
        tf.nn.l2_loss(hj_emb),
        ])

    self.loss = tf.reduce_sum(
        -tf.math.log(tf.clip_by_value(tf.math.sigmoid(self.x), 1e-8, 1.0))
        ) + self.config['regulation_rate'] * l2_norm