package itn.let.solr.search.impl; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.commons.lang.time.DateUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateFormatUtils; import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrQuery.ORDER; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.HttpSolrClient; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.client.solrj.response.SpellCheckResponse.Suggestion; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.params.CommonParams; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.ui.ModelMap; import itn.let.solr.search.service.SearchService; public class SearchServiceImpl implements InitializingBean, SearchService { Logger log = LoggerFactory.getLogger(this.getClass()); @Value("${Globals.Solr.url}") private String SERVER_URL; private Set introFieldSet; private Set policyFieldSet; private Set safetyFieldSet; private Set noticeFieldSet; private Set communityFieldSet; private Set infoFieldSet; private Set fileFieldSet; @SuppressWarnings("unused") private Set boardFieldSet; @SuppressWarnings("unused") private Set webpageFieldSet; @SuppressWarnings("unused") private Set itn_BoardFieldSet; @SuppressWarnings("unused") private Set itn_ContentFieldSet; private Map> fieldMap = new HashMap>(); private final String REGEX = "^[1-9a-zA-Zㄱ-ㅎㅏ-ㅣ가-힣| *]+$"; private final String SPECIAL_REGEX = "[^ㄱ-ㅎ\uAC00-\uD7A3xfe0-9a-zA-Z\\s]"; private Pattern pattern = Pattern.compile(REGEX); public SearchServiceImpl(){ } @Override public void afterPropertiesSet() throws Exception { fieldMap.put(SOLR_CORE.INTRO.getValue(), introFieldSet); fieldMap.put(SOLR_CORE.POLICY.getValue(), policyFieldSet); fieldMap.put(SOLR_CORE.SAFETY.getValue(), safetyFieldSet); fieldMap.put(SOLR_CORE.NOTICE.getValue(), noticeFieldSet); fieldMap.put(SOLR_CORE.COMMUNITY.getValue(), communityFieldSet); fieldMap.put(SOLR_CORE.INFO.getValue(), infoFieldSet); /*fieldMap.put(SOLR_CORE.FILE.getValue(), fileFieldSet); fieldMap.put(SOLR_CORE.WEBPAGE.getValue(), webpageFieldSet); fieldMap.put(SOLR_CORE.BOARD.getValue(), boardFieldSet); fieldMap.put(SOLR_CORE.ITN_BOARD.getValue(), itn_BoardFieldSet); fieldMap.put(SOLR_CORE.ITN_CONTENT.getValue(), itn_ContentFieldSet);*/ } @Override public Set suggest(Map commandMap) throws Exception { String q = (String)commandMap.get("q"); if (StringUtils.isBlank(q)) { return Collections.emptySet(); } q = URLDecoder.decode(q, "UTF-8"); Set resultList = new LinkedHashSet(); SolrQuery query = new SolrQuery(); query.setParam(CommonParams.QT, "/suggest"); query.setQuery(q); String serverUrl = SERVER_URL.endsWith("/") ? SERVER_URL : SERVER_URL + "/"; for(SOLR_CORE sc : SOLR_CORE.values()){ SolrClient client = null; try { client = new HttpSolrClient(serverUrl+sc.getValue()); QueryResponse rsp = client.query(query); if (rsp != null) { List suggestions = rsp.getSpellCheckResponse().getSuggestions(); if( CollectionUtils.isNotEmpty(suggestions) ){ for(Suggestion s : suggestions){ resultList.addAll(s.getAlternatives()); } } } } catch (SolrServerException e) { e.printStackTrace(); } finally { IOUtils.closeQuietly(client); } } log.debug("{} - {}", serverUrl, resultList); return resultList; } @Override public void search(Map commandMap, ModelMap model) throws Exception { String q = (String)commandMap.get("q"); if ( StringUtils.isBlank(q) ) { q = (String)commandMap.get("q2"); } if (StringUtils.isNotBlank(q)) { Matcher matcher = pattern.matcher(q); if( matcher.find() ) { commandMap.put("srchwrd", q); } } Map>> resultMap = new HashMap>>(); Map resultCntMap = new HashMap(); long totalCount = 0; for (SOLR_CORE sc : SOLR_CORE.values()) { resultCntMap.put(sc.getValue(), new Long(0)); resultMap.put(sc.getValue(), Collections.>emptyList()); List> resultList = getResultList(sc, fieldMap.get(sc.getValue()), commandMap); long numFound = 0; if ( !CollectionUtils.isEmpty(resultList) ) { Map result = resultList.get(0); numFound = NumberUtils.toLong(result.get("numFound").toString()); totalCount += numFound; resultCntMap.put(sc.getValue(), numFound); resultMap.put(sc.getValue(), resultList); } if ( sc.getValue().equals((String)commandMap.get("rangeView")) ) { } } model.addAttribute("resultMap", resultMap); model.addAttribute("resultCntMap", resultCntMap); model.addAttribute("totalCount", totalCount); } private List> getResultList(SOLR_CORE core, Set fieldSet, Map commandMap){ List> resultList = new ArrayList>(); String serverUrl = SERVER_URL.endsWith("/") ? SERVER_URL : SERVER_URL + "/"; HttpSolrClient client = null; SolrQuery query = makeQuery(core, commandMap, fieldSet); log.debug("{}{}", serverUrl, query); try { client = new HttpSolrClient(serverUrl+core.getValue()); client.setConnectionTimeout(1000); QueryResponse rsp = client.query(query); Iterator iter = rsp.getResults().iterator(); long numFound = rsp.getResults().getNumFound(); while (iter.hasNext()) { Map resultMap = new HashMap<>(); SolrDocument resultDoc = iter.next(); for(String field : fieldSet){ resultMap.put(field, resultDoc.getFieldValue(field)); } Object id = resultDoc.getFieldValue("id"); Map>> highlighting = rsp.getHighlighting(); if( highlighting.get(id.toString()) != null ){ Map> highlightSnippetMap = highlighting.get(id); String hlFl = StringUtils.defaultString((String)commandMap.get("hl.fl"), "text"); List highlightSnippets = highlightSnippetMap.get(hlFl); if( CollectionUtils.isNotEmpty(highlightSnippets) ){ resultMap.put("hl", highlightSnippets.get(0)); } List nttSjHl = highlightSnippetMap.get("nttSj"); if( CollectionUtils.isNotEmpty(nttSjHl) ){ resultMap.put("nttSjHl", nttSjHl.get(0)); } } resultMap.put("numFound", numFound); resultList.add(resultMap); } } catch (Exception e) { e.printStackTrace(); } finally { IOUtils.closeQuietly(client); } return resultList; } private SolrQuery makeQuery(SOLR_CORE core, Map commandMap, Set fieldSet){ SolrQuery query = new SolrQuery(); String q = StringUtils.defaultString((String)commandMap.get("q")); q = q.replaceAll(SPECIAL_REGEX, ""); String re = (String)commandMap.get("re"); String sdate = (String)commandMap.get("sdate"); String edate = (String)commandMap.get("edate"); String date = (String)commandMap.get("date"); int pageIndex = 1; String rangeView = (String)commandMap.get("rangeView"); if (core.getValue().equals(rangeView)) { String pi = (String)commandMap.get("pageIndex"); if (StringUtils.isNotBlank(pi)) { pageIndex = NumberUtils.toInt(pi, 1); } } int pageUnit = 10; int start = (pageIndex -1) * pageUnit; query.setStart(start); StringBuilder _q = new StringBuilder(); if( "Y".equals(re) ){ String prevQ = (String)commandMap.get("prevQ"); if( StringUtils.isNotBlank(q) && StringUtils.isNotBlank(prevQ) ){ _q.append(q).append(" AND ").append(prevQ); } else if( StringUtils.isNotBlank(prevQ) ){ _q.append(prevQ); } else if( StringUtils.isNotBlank(q) ){ _q.append(q); } else{ _q.append("*:*"); } } else{ if( !StringUtils.isNotBlank(q) ){ _q.append("*:*"); } else{ _q.append(q); } } if( !"*:*".equals(_q.toString()) ){ _q.insert(0, "*"); _q.append("*"); } if (StringUtils.isNotBlank(sdate) && StringUtils.isNotBlank(edate)) { query.addFilterQuery("registDt:["+sdate+" TO "+edate+"]"); } if (StringUtils.isNotBlank(date)) { Date today = new Date(); String e = DateFormatUtils.format(today, "yyyy-mm-dd"); String s = ""; if ("1d".equals(date)) { s = DateFormatUtils.format(DateUtils.addDays(today, -1), "yyyy-mm-dd"); } else if ("1w".equals(date)) { s = DateFormatUtils.format(DateUtils.addDays(today, -7), "yyyy-mm-dd"); } else if ("1m".equals(date)) { s = DateFormatUtils.format(DateUtils.addMonths(today, -1), "yyyy-mm-dd"); } else if ("3m".equals(date)) { s = DateFormatUtils.format(DateUtils.addMonths(today, -3), "yyyy-mm-dd"); } else if ("6m".equals(date)) { s = DateFormatUtils.format(DateUtils.addMonths(today, -6), "yyyy-mm-dd"); } query.addFilterQuery("registDt:["+s+" TO "+e+"]"); } String categoryData = (String)commandMap.get("categoryData"); log.debug("categoryData : {}", categoryData); if (categoryData != null) { String[] data = StringUtils.split(categoryData, ","); for (String c : data) { query.addFilterQuery("category:" + c); } } String hlFl = StringUtils.defaultString((String)commandMap.get("hl.fl"), "text"); String hlFragsize = StringUtils.defaultString((String)commandMap.get("hl.fragsize"), "140"); query.setQuery(_q.toString()); query.setHighlight(true).setHighlightSnippets(1); query.setParam("hl.fl", hlFl, "nttSj"); query.setParam("hl.fragsize", hlFragsize); Map m = getSortMap(commandMap, fieldSet); if( m != null ) { for (Map.Entry entry : m.entrySet()) { query.addSort(entry.getKey(), entry.getValue()); } } return query; } private Map getSortMap(Map commandMap, Set fieldSet) { Map sortMap = new HashMap(); String s = (String)commandMap.get("s"); if( StringUtils.isNotBlank(s) ){ String[] data = StringUtils.split(s, "^"); for (String d : data) { String[] sortField = StringUtils.split(d, "|"); if ( !"default".equals(sortField[0]) ) { if (fieldSet != null && fieldSet.contains(sortField[0])) { String field = sortField[0]; ORDER order = null; if (sortField[1].equals("asc")) { order = SolrQuery.ORDER.asc; } else { order = SolrQuery.ORDER.desc; } sortMap.put(field, order); } } } } return sortMap; } public Set getFileFieldSet() { return fileFieldSet; } public void setFileFieldSet(Set fileFieldSet) { this.fileFieldSet = fileFieldSet; } public void setBoardFieldSet(Set boardFieldSet) { this.boardFieldSet = boardFieldSet; } public void setWebpageFieldSet(Set webpageFieldSet) { this.webpageFieldSet = webpageFieldSet; } public void setItn_BoardFieldSet(Set itn_BoardFieldSet) { this.itn_BoardFieldSet = itn_BoardFieldSet; } public void setItn_ContentFieldSet(Set itn_ContentFieldSet) { this.itn_ContentFieldSet = itn_ContentFieldSet; } public Set getIntroFieldSet() { return introFieldSet; } public void setIntroFieldSet(Set introFieldSet) { this.introFieldSet = introFieldSet; } public Set getPolicyFieldSet() { return policyFieldSet; } public void setPolicyFieldSet(Set policyFieldSet) { this.policyFieldSet = policyFieldSet; } public Set getSafetyFieldSet() { return safetyFieldSet; } public void setSafetyFieldSet(Set safetyFieldSet) { this.safetyFieldSet = safetyFieldSet; } public Set getNoticeFieldSet() { return noticeFieldSet; } public void setNoticeFieldSet(Set noticeFieldSet) { this.noticeFieldSet = noticeFieldSet; } public Set getCommunityFieldSet() { return communityFieldSet; } public void setCommunityFieldSet(Set communityFieldSet) { this.communityFieldSet = communityFieldSet; } public Set getInfoFieldSet() { return infoFieldSet; } public void setInfoFieldSet(Set infoFieldSet) { this.infoFieldSet = infoFieldSet; } }