// @RequiresPermissions("topic:index:rebuild")
 public void rebuild() throws IOException {
   Sql sql = Sqls.queryString("select id from t_topic where tp='ask'");
   dao.execute(sql);
   luceneIndex.writer.deleteAll();
   String[] topicIds = sql.getObject(String[].class);
   for (String topicId : topicIds) {
     Topic topic = dao.fetch(Topic.class, topicId);
     bigContentService.fill(topic);
     _add(topic);
   }
   luceneIndex.writer.commit();
 }
  protected void _add(Topic topic) {
    if (topic == null) return; // 虽然不太可能,还是预防一下吧
    // 暂时不索引评论
    dao.fetchLinks(topic, "replies");
    Document document;
    document = new Document();
    Field field;
    FieldType fieldType;

    // 先加入id
    fieldType = new FieldType();
    fieldType.setIndexed(true); // 索引
    fieldType.setStored(true); // 存储
    fieldType.setStoreTermVectors(true);
    fieldType.setTokenized(true);
    fieldType.setStoreTermVectorPositions(true); // 存储位置
    fieldType.setStoreTermVectorOffsets(true); // 存储偏移量
    field = new Field("id", topic.getId(), fieldType);
    document.add(field);

    // 加入标题
    fieldType = new FieldType();
    fieldType.setIndexed(true); // 索引
    fieldType.setStored(true); // 存储
    fieldType.setStoreTermVectors(true);
    fieldType.setTokenized(true);
    fieldType.setStoreTermVectorPositions(true); // 存储位置
    fieldType.setStoreTermVectorOffsets(true); // 存储偏移量
    field = new Field("title", topic.getTitle(), fieldType);
    document.add(field);

    // 加入文章内容
    fieldType = new FieldType();
    fieldType.setIndexed(true); // 索引
    fieldType.setStored(false); // 存储
    fieldType.setStoreTermVectors(true);
    fieldType.setTokenized(true);
    fieldType.setStoreTermVectorPositions(true); // 存储位置
    fieldType.setStoreTermVectorOffsets(true); // 存储偏移量
    field = new Field("content", topic.getContent(), fieldType);
    document.add(field);

    StringBuilder sb = new StringBuilder();
    if (topic.getReplies() != null) {
      for (TopicReply reply : topic.getReplies()) {
        if (reply == null) continue;
        bigContentService.fill(reply);
        if (reply.getContent() != null) {
          if (sb.length() + reply.getContent().length() > (IndexWriter.MAX_TERM_LENGTH / 3)) {
            break;
          }
          sb.append(reply.getContent());
        }
      }
    }
    fieldType = new FieldType();
    fieldType.setIndexed(true); // 索引
    fieldType.setStored(false); // 存储
    fieldType.setStoreTermVectors(true);
    fieldType.setTokenized(true);
    fieldType.setStoreTermVectorPositions(true); // 存储位置
    fieldType.setStoreTermVectorOffsets(true); // 存储偏移量

    field = new Field("reply", sb.toString(), fieldType);
    document.add(field);

    try {
      luceneIndex.writer.addDocument(document);
    } catch (IOException e) {
      log.debug("add to index fail : id=" + topic.getId());
    } catch (Error e) {
      log.debug("add to index fail : id=" + topic.getId());
    }
  }