@Override
  public SearchResult search(CrescentSearchRequestWrapper csrw) throws IOException {

    SearchResult searchResult = new SearchResult();
    int totalHitsCount = 0;
    String errorMessage = "SUCCESS";
    int errorCode = 0;

    // 5page * 50
    int numOfHits = csrw.getDefaultHitsPage() * csrw.getHitsForPage();
    IndexSearcher indexSearcher = null;
    SearcherManager searcherManager =
        crescentSearcherManager.getSearcherManager(csrw.getCollectionName());

    try {
      indexSearcher = searcherManager.acquire();

      Query query = csrw.getQuery();
      Filter filter = csrw.getFilter();
      Sort sort = csrw.getSort();

      logger.debug("query : {}", query);
      logger.debug("filter : {}", filter);
      logger.debug("sort : {}", sort);

      long startTime = System.currentTimeMillis();
      TopDocs topDocs = null;

      if (sort == null) {
        topDocs = indexSearcher.search(query, filter, numOfHits);
      } else {
        topDocs = indexSearcher.search(query, filter, numOfHits, sort);
      }

      long endTime = System.currentTimeMillis();

      // 전체 검색 건수
      totalHitsCount = topDocs.totalHits;

      LogInfo logInfo = new LogInfo();
      logInfo.setCollectionName(csrw.getCollectionName());
      logInfo.setElaspedTimeMil(endTime - startTime);
      logInfo.setKeyword(csrw.getKeyword());
      logInfo.setPageNum(csrw.getPageNum());
      logInfo.setPcid(csrw.getPcId());
      logInfo.setQuery(query);
      logInfo.setSort(csrw.getSort());
      logInfo.setTotalCount(totalHitsCount);
      logInfo.setUserId(csrw.getUserId());
      logInfo.setUserIp(csrw.getUserIp());
      logInfo.setFilter(csrw.getFilter());

      CrescentLogger.logging(logInfo);

      logger.debug("Total Hits Count : {} ", totalHitsCount);

      ScoreDoc[] hits = topDocs.scoreDocs;

      // 총 검색건수와 실제 보여줄 document의 offset (min ~ max)를 비교해서 작은 것을 가져옴
      int endOffset = Math.min(totalHitsCount, csrw.getStartOffSet() + csrw.getHitsForPage());

      if (endOffset > hits.length) {
        logger.debug("기본 설정된 검색건수보다 더 검색을 원하므로, 전체를 대상으로 검색합니다.");

        if (sort == null) {
          topDocs = indexSearcher.search(query, filter, totalHitsCount);
        } else {
          topDocs = indexSearcher.search(query, filter, totalHitsCount, sort);
        }

        hits = topDocs.scoreDocs;
      }

      int startOffset = csrw.getStartOffSet();
      endOffset = Math.min(hits.length, startOffset + csrw.getHitsForPage());

      // for(int i = startOffset; i < endOffset; i++) {
      //	Document doc = indexSearcher.doc(hits[i].doc);
      //	resultDocumentList.add(doc);
      // }

      logger.debug(
          "start offset : [{}], end offset : [{}], total : [{}], numOfHits :[{}]",
          new Object[] {csrw.getStartOffSet(), endOffset, totalHitsCount, numOfHits});
      logger.debug("hits count : [{}]", hits.length);
      logger.debug(
          "startOffset + hitsPerPage : [{}]", csrw.getStartOffSet() + csrw.getHitsForPage());

      if (totalHitsCount > 0) {
        List<Map<String, String>> resultList = new ArrayList<Map<String, String>>();
        Map<String, Object> result = new HashMap<String, Object>();

        CrescentFastVectorHighlighter highlighter = new CrescentFastVectorHighlighter();

        CrescentCollectionHandler collectionHandler =
            SpringApplicationContext.getBean(
                "crescentCollectionHandler", CrescentCollectionHandler.class);
        CrescentCollection collection =
            collectionHandler
                .getCrescentCollections()
                .getCrescentCollection(csrw.getCollectionName());

        // int docnum = 0;
        for (int i = startOffset; i < endOffset; i++) {

          Map<String, String> resultMap = new HashMap<String, String>();

          for (CrescentCollectionField field : collection.getFields()) {
            String value = null;

            if (field.isStore() && !field.isNumeric()) {

              // 필드별 결과를 가져온다.
              value =
                  highlighter.getBestFragment(
                      indexSearcher.getIndexReader(), hits[i].doc, query, field.getName());
            }

            if (value == null || value.length() == 0) {
              Document doc = indexSearcher.doc(hits[i].doc);
              value = doc.get(field.getName());
            }

            resultMap.put(field.getName(), value);
          }

          resultList.add(resultMap);
        }

        result.put("total_count", totalHitsCount);
        result.put("result_list", resultList);
        result.put("error_code", errorCode);
        result.put("error_msg", errorMessage);

        logger.debug("result list {}", resultList);

        searchResult.setResultList(resultList);
        searchResult.setTotalHitsCount(totalHitsCount);
        searchResult.setSearchResult(result);

      } else {

        // 결과없음
        Map<String, Object> result = new HashMap<String, Object>();
        List<Map<String, String>> resultList = new ArrayList<Map<String, String>>();

        result.put("total_count", totalHitsCount);
        result.put("result_list", resultList);
        result.put("error_code", errorCode);
        result.put("error_msg", errorMessage);

        logger.debug("result list {}", resultList);

        searchResult.setResultList(resultList);
        searchResult.setTotalHitsCount(0);
        searchResult.setSearchResult(result);
      }

    } catch (Exception e) {

      logger.error("error in CrescentDefaultDocSearcher : ", e);

      Map<String, Object> result = new HashMap<String, Object>();
      List<Map<String, String>> resultList = new ArrayList<Map<String, String>>();

      result.put("total_count", totalHitsCount);
      result.put("result_list", resultList);
      result.put("error_code", errorCode);
      result.put("error_msg", errorMessage);

      logger.error("검색 중 에러 발생함. {}", e);

      searchResult.setErrorCode(errorCode);
      searchResult.setErrorMsg(errorMessage);
      searchResult.setSearchResult(result);
      searchResult.setResultList(resultList);

      return searchResult;

    } finally {
      searcherManager.release(indexSearcher);
      indexSearcher = null;
    }

    return searchResult;
  }
  @Override
  public boolean reload(String collectionName, String topRankingField) {
    if (collectionName == null) {
      return false;
    }

    CrescentCollectionHandler collectionHandler =
        SpringApplicationContext.getBean(
            "crescentCollectionHandler", CrescentCollectionHandler.class);

    CrescentCollection collection =
        collectionHandler.getCrescentCollections().getCrescentCollection(collectionName);

    if (collection == null) {
      logger.debug("doesn't Collection Info => {}", collectionName);
      init(View.Overview);
      return false;
    }

    if (topRankingField == null) {
      if (collection.getDefaultSearchFields().get(0) != null) {
        topRankingField = collection.getDefaultSearchFields().get(0).getName();
      } else {
        logger.debug("doesn't defaultSearchField => {}", collectionName);
        init(View.Overview);
        return false;
      }
    }

    List<String> fieldName = new ArrayList<String>();
    for (CrescentCollectionField field : collection.getFields()) fieldName.add(field.getName());
    TopRankingQueue topRankingQueue =
        new TopRankingQueue(DEFAULT_TOPRANKING_TERM, new RankingTermComparator());

    try {
      Directory directory = FSDirectory.open(new File(collection.getIndexingDirectory()));
      IndexReader reader = IndexReader.open(directory);

      TermEnum terms = reader.terms();

      int termFreq = 0;
      int termCount = 0;
      Term beforeTerm = null;
      // init term count
      fieldTermCount.clear();
      for (CrescentCollectionField field : collection.getFields())
        fieldTermCount.put(field.getName(), 0);
      topRankingQueue.clear();

      while (terms.next()) {
        Term currTerm = terms.term();
        if (beforeTerm == null) {
          beforeTerm = currTerm;
        }

        if (beforeTerm.field() == currTerm.field()) {
          termCount++;
        } else {
          fieldTermCount.put(beforeTerm.field(), termCount);
          termCount = 1;
          beforeTerm = currTerm;
        }

        TermDocs termDocs = reader.termDocs(currTerm);

        while (termDocs.next()) {
          if (currTerm.field().equals(topRankingField)) {
            RankingTerm e = new RankingTerm(currTerm.text(), currTerm.field(), termDocs.freq());
            topRankingQueue.add(e);
          }
        }
        termFreq++;
      }
      if (beforeTerm != null) fieldTermCount.put(beforeTerm.field(), termCount);

      terms.close();
      result.put("numOfTerm", termFreq);
      result.put("numOfDoc", reader.numDocs());
      result.put("hasDel", reader.hasDeletions());
      result.put("isOptimize", reader.isOptimized());
      result.put("indexVersion", reader.getVersion());
      result.put("lastModify", new Date(IndexReader.lastModified(directory)));
    } catch (IOException e) {
      e.printStackTrace();
      return false;
    }
    if (topRankingQueue.size() != 0) {
      topRankingTerms = topRankingQueue.toArray();
      Arrays.sort(topRankingTerms);
    }
    result.put("collectionName", collectionName);
    result.put("indexName", collection.getIndexingDirectory());
    result.put("numOfField", collection.getFields().size());
    result.put("termCount", fieldTermCount);
    result.put("topRanking", topRankingTerms);
    result.put("fieldName", fieldName);

    return true;
  }