diff --git a/src/main/java/org/codelibs/fess/api/suggest/SuggestApiManager.java b/src/main/java/org/codelibs/fess/api/suggest/SuggestApiManager.java index 2de24a392..d484ce3b8 100644 --- a/src/main/java/org/codelibs/fess/api/suggest/SuggestApiManager.java +++ b/src/main/java/org/codelibs/fess/api/suggest/SuggestApiManager.java @@ -68,10 +68,7 @@ public class SuggestApiManager extends BaseApiManager { final SuggestResponse suggestResponse = builder.execute().getResponse(); buf.append("\"result\":{"); - // TODO removed? - // buf.append("\"index\":\"").append(suggestResponse.getIndex()).append('\"'); - - buf.append(",\"took\":\"").append(suggestResponse.getTookMs()).append('\"'); + buf.append("\"took\":\"").append(suggestResponse.getTookMs()).append('\"'); buf.append(",\"total\":\"").append(suggestResponse.getTotal()).append('\"'); diff --git a/src/main/java/org/codelibs/fess/exec/SuggestCreater.java b/src/main/java/org/codelibs/fess/exec/SuggestCreater.java new file mode 100644 index 000000000..bd998d24d --- /dev/null +++ b/src/main/java/org/codelibs/fess/exec/SuggestCreater.java @@ -0,0 +1,137 @@ +package org.codelibs.fess.exec; + +import org.codelibs.core.lang.StringUtil; +import org.codelibs.fess.Constants; +import org.codelibs.fess.crawler.client.EsClient; +import org.codelibs.fess.es.client.FessEsClient; +import org.codelibs.fess.helper.SuggestHelper; +import org.codelibs.fess.util.ComponentUtil; +import org.kohsuke.args4j.CmdLineException; +import org.kohsuke.args4j.CmdLineParser; +import org.kohsuke.args4j.Option; +import org.lastaflute.di.core.SingletonLaContainer; +import org.lastaflute.di.core.factory.SingletonLaContainerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Resource; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; + +public class SuggestCreater implements Serializable { + private static final long serialVersionUID = 1L; + + private static final Logger logger = LoggerFactory.getLogger(Crawler.class); + + @Resource + public FessEsClient fessEsClient; + + protected static class Options { + @Option(name = "-s", aliases = "--sessionId", metaVar = "sessionId", usage = "Session ID") + protected String sessionId; + + @Option(name = "-n", aliases = "--name", metaVar = "name", usage = "Name") + protected String name; + + protected Options() { + // noghing + } + } + + public static void main(final String[] args) { + final Options options = new Options(); + + final CmdLineParser parser = new CmdLineParser(options); + try { + parser.parseArgument(args); + } catch (final CmdLineException e) { + System.err.println(e.getMessage()); // NOPMD + System.err.println("java " + Crawler.class.getCanonicalName() // NOPMD + + " [options...] arguments..."); + parser.printUsage(System.err); + return; + } + + final String transportAddresses = System.getProperty(Constants.FESS_ES_TRANSPORT_ADDRESSES); + if (StringUtil.isNotBlank(transportAddresses)) { + System.setProperty(EsClient.TRANSPORT_ADDRESSES, transportAddresses); + } + final String clusterName = System.getProperty(Constants.FESS_ES_CLUSTER_NAME); + if (StringUtil.isNotBlank(clusterName)) { + System.setProperty(EsClient.CLUSTER_NAME, clusterName); + } + + int exitCode; + try { + SingletonLaContainerFactory.setConfigPath("app.xml"); + SingletonLaContainerFactory.init(); + + final Thread shutdownCallback = new Thread("ShutdownHook") { + @Override + public void run() { + if (logger.isDebugEnabled()) { + logger.debug("Destroying LaContainer.."); + } + SingletonLaContainerFactory.destroy(); + } + }; + Runtime.getRuntime().addShutdownHook(shutdownCallback); + exitCode = process(options); + } catch (final Throwable t) { // NOPMD + logger.error("Suggest creater does not work correctly.", t); + exitCode = Constants.EXIT_FAIL; + } finally { + SingletonLaContainerFactory.destroy(); + } + + logger.info("Finished suggestCreater."); + System.exit(exitCode); + } + + private static int process(final Options options) { + final SuggestCreater creater = SingletonLaContainer.getComponent(SuggestCreater.class); + final LocalDateTime startTime = LocalDateTime.now(); + int ret = creater.create(); + if (ret == 0) { + ret = creater.purge(startTime); + } + return ret; + } + + private int create() { + logger.info("Start create suggest document."); + + final AtomicInteger result = new AtomicInteger(1); + final CountDownLatch latch = new CountDownLatch(1); + + final SuggestHelper suggestHelper = ComponentUtil.getSuggestHelper(); + suggestHelper.indexFromDocuments(ret -> { + logger.info("Success index from documents."); + result.set(0); + latch.countDown(); + }, t -> { + logger.error("Failed to update suggest index.", t); + latch.countDown(); + }); + + try { + latch.await(); + } catch (InterruptedException ignore) {} + + return result.get(); + } + + private int purge(LocalDateTime time) { + final SuggestHelper suggestHelper = ComponentUtil.getSuggestHelper(); + try { + suggestHelper.purge(time); + return 0; + } catch (Exception e) { + logger.info("Purge error.", e); + return 1; + } + } + +} diff --git a/src/main/java/org/codelibs/fess/helper/SuggestHelper.java b/src/main/java/org/codelibs/fess/helper/SuggestHelper.java index 8f94200c4..966bcacff 100644 --- a/src/main/java/org/codelibs/fess/helper/SuggestHelper.java +++ b/src/main/java/org/codelibs/fess/helper/SuggestHelper.java @@ -15,10 +15,11 @@ */ package org.codelibs.fess.helper; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; import javax.annotation.PostConstruct; import javax.annotation.Resource; @@ -31,6 +32,15 @@ import org.codelibs.fess.es.config.exentity.SuggestBadWord; import org.codelibs.fess.es.log.exentity.SearchFieldLog; import org.codelibs.fess.es.log.exentity.SearchLog; import org.codelibs.fess.suggest.Suggester; +import org.codelibs.fess.suggest.concurrent.Deferred; +import org.codelibs.fess.suggest.constants.FieldNames; +import org.codelibs.fess.suggest.entity.SuggestItem; +import org.codelibs.fess.suggest.index.contents.document.DocumentReader; +import org.codelibs.fess.suggest.index.contents.document.ESSourceReader; +import org.codelibs.fess.suggest.settings.SuggestSettings; +import org.codelibs.fess.suggest.util.SuggestUtil; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,16 +65,25 @@ public class SuggestHelper { public String[] roleFieldNames = { "role" }; + public String[] contentsIndex = { "content", "title" }; + private static final String TEXT_SEP = " "; protected Suggester suggester; + protected final AtomicBoolean initialized = new AtomicBoolean(false); + @PostConstruct public void init() { final Thread th = new Thread(() -> { fessEsClient.admin().cluster().prepareHealth().setWaitForYellowStatus().execute().actionGet(); suggester = Suggester.builder().build(fessEsClient, fieldHelper.docIndex); + suggester.settings().array().delete(SuggestSettings.DefaultKeys.SUPPORTED_FIELDS); + for (final String field : contentsIndex) { + suggester.settings().array().add(SuggestSettings.DefaultKeys.SUPPORTED_FIELDS, field); + } suggester.createIndexIfNothing(); + initialized.set(true); }); th.start(); } @@ -105,6 +124,49 @@ public class SuggestHelper { suggester.refresh(); } + public void indexFromDocuments(final Consumer success, final Consumer error) { + while (!initialized.get()) { + try { + Thread.sleep(100); + } catch (Exception e) { + error.accept(e); + return; + } + } + + createFessIndexTest(); + + DocumentReader reader = new ESSourceReader(fessEsClient, suggester.settings(), fieldHelper.docIndex, fieldHelper.docType); + + suggester.indexer().indexFromDocument(reader, 2, 100).done(response -> { + suggester.refresh(); + + //TODO delete old doc + + success.accept(true); + }).error(t -> error.accept(t)); + } + + public void purge(LocalDateTime time) { + BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); + boolQueryBuilder.must(QueryBuilders.rangeQuery(FieldNames.TIMESTAMP).lt(time.format(DateTimeFormatter.BASIC_ISO_DATE))); + + boolQueryBuilder.must(QueryBuilders.termQuery(FieldNames.KINDS, SuggestItem.Kind.DOCUMENT.toString())); + boolQueryBuilder.mustNot(QueryBuilders.termQuery(FieldNames.KINDS, SuggestItem.Kind.QUERY.toString())); + boolQueryBuilder.must(QueryBuilders.termQuery(FieldNames.KINDS, SuggestItem.Kind.USER.toString())); + + SuggestUtil.deleteByQuery(fessEsClient, suggester.getIndex(), suggester.getType(), boolQueryBuilder); + } + + public void createFessIndexTest() { + Map source = new HashMap<>(); + source.put("content", "aaa bbbb baa aaa aaaa,,, aaa bbbb 検索 検索 「検索」"); + source.put("title", "shirobako shirobako"); + + fessEsClient.prepareIndex(fieldHelper.docIndex, fieldHelper.docType).setSource(source).execute().actionGet(); + fessEsClient.admin().indices().prepareRefresh().execute().actionGet(); + } + public void refreshWords() { deleteAllBadWord(); storeAllElevateWords(); diff --git a/src/main/java/org/codelibs/fess/job/SuggestJob.java b/src/main/java/org/codelibs/fess/job/SuggestJob.java new file mode 100644 index 000000000..2cd4223e5 --- /dev/null +++ b/src/main/java/org/codelibs/fess/job/SuggestJob.java @@ -0,0 +1,250 @@ +package org.codelibs.fess.job; + +import org.apache.commons.lang3.SystemUtils; +import org.codelibs.core.lang.StringUtil; +import org.codelibs.fess.Constants; +import org.codelibs.fess.exception.FessSystemException; +import org.codelibs.fess.exec.SuggestCreater; +import org.codelibs.fess.helper.JobHelper; +import org.codelibs.fess.helper.SystemHelper; +import org.codelibs.fess.util.ComponentUtil; +import org.codelibs.fess.util.InputStreamThread; +import org.codelibs.fess.util.JobProcess; +import org.lastaflute.di.core.SingletonLaContainer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ServletContext; +import java.io.File; +import java.io.FilenameFilter; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class SuggestJob { + private static final Logger logger = LoggerFactory.getLogger(SuggestJob.class); + + protected JobExecutor jobExecutor; + + protected String sessionId; + + protected boolean useLocaleElasticsearch = true; + + protected String logFilePath; + + protected int retryCountToDeleteTempDir = 10; + + protected long retryIntervalToDeleteTempDir = 5000; + + public SuggestJob jobExecutor(final JobExecutor jobExecutor) { + this.jobExecutor = jobExecutor; + return this; + } + + public SuggestJob sessionId(final String sessionId) { + this.sessionId = sessionId; + return this; + } + + public String execute(final JobExecutor jobExecutor) { + jobExecutor(jobExecutor); + return execute(); + } + + public String execute() { + final StringBuilder resultBuf = new StringBuilder(); + + if (sessionId == null) { // create session id + final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); + sessionId = sdf.format(new Date()); + } + resultBuf.append("Session Id: ").append(sessionId).append("\n"); + if (jobExecutor != null) { + jobExecutor.addShutdownListener(() -> ComponentUtil.getJobHelper().destroyCrawlerProcess(sessionId)); + } + + try { + executeSuggestCreater(); + ComponentUtil.getKeyMatchHelper().update(); + } catch (final FessSystemException e) { + throw e; + } catch (final Exception e) { + throw new FessSystemException("Failed to execute a crawl job.", e); + } + + return resultBuf.toString(); + + } + + protected void executeSuggestCreater() { + final List suggestCreaterCmdList = new ArrayList<>(); + final String cpSeparator = SystemUtils.IS_OS_WINDOWS ? ";" : ":"; + final ServletContext servletContext = SingletonLaContainer.getComponent(ServletContext.class); + final SystemHelper systemHelper = ComponentUtil.getSystemHelper(); + final JobHelper jobHelper = ComponentUtil.getJobHelper(); + + suggestCreaterCmdList.add(systemHelper.getJavaCommandPath()); + + // -cp + suggestCreaterCmdList.add("-cp"); + final StringBuilder buf = new StringBuilder(); + // WEB-INF/suggest/resources + buf.append("WEB-INF"); + buf.append(File.separator); + buf.append("suggest"); + buf.append(File.separator); + buf.append("resources"); + buf.append(cpSeparator); + // WEB-INF/classes + buf.append("WEB-INF"); + buf.append(File.separator); + buf.append("classes"); + // target/classes + final String userDir = System.getProperty("user.dir"); + final File targetDir = new File(userDir, "target"); + final File targetClassesDir = new File(targetDir, "classes"); + if (targetClassesDir.isDirectory()) { + buf.append(cpSeparator); + buf.append(targetClassesDir.getAbsolutePath()); + } + // WEB-INF/lib + appendJarFile(cpSeparator, buf, new File(servletContext.getRealPath("/WEB-INF/lib")), "WEB-INF/lib" + File.separator); + // WEB-INF/crawler/lib + appendJarFile(cpSeparator, buf, new File(servletContext.getRealPath("/WEB-INF/suggest/lib")), "WEB-INF/suggest" + File.separator + + "lib" + File.separator); + final File targetLibDir = new File(targetDir, "fess" + File.separator + "WEB-INF" + File.separator + "lib"); + if (targetLibDir.isDirectory()) { + appendJarFile(cpSeparator, buf, targetLibDir, targetLibDir.getAbsolutePath() + File.separator); + } + suggestCreaterCmdList.add(buf.toString()); + + if (useLocaleElasticsearch) { + final String transportAddresses = System.getProperty(Constants.FESS_ES_TRANSPORT_ADDRESSES); + if (StringUtil.isNotBlank(transportAddresses)) { + suggestCreaterCmdList.add("-D" + Constants.FESS_ES_TRANSPORT_ADDRESSES + "=" + transportAddresses); + } + final String clusterName = System.getProperty(Constants.FESS_ES_CLUSTER_NAME); + if (StringUtil.isNotBlank(clusterName)) { + suggestCreaterCmdList.add("-D" + Constants.FESS_ES_CLUSTER_NAME + "=" + clusterName); + } + } + + suggestCreaterCmdList.add("-Dfess.suggest.process=true"); + if (logFilePath == null) { + final String value = System.getProperty("fess.log.path"); + logFilePath = value != null ? value : new File(targetDir, "logs").getAbsolutePath(); + } + suggestCreaterCmdList.add("-Dfess.log.path=" + logFilePath); + addSystemProperty(suggestCreaterCmdList, "lasta.env", null, null); + addSystemProperty(suggestCreaterCmdList, "fess.log.name", "fess-suggest", "-suggest"); + addSystemProperty(suggestCreaterCmdList, "fess.log.level", null, null); + if (systemHelper.getCrawlerJavaOptions() != null) { + for (final String value : systemHelper.getCrawlerJavaOptions()) { + suggestCreaterCmdList.add(value); + } + } + + File ownTmpDir = null; + if (systemHelper.isUseOwnTmpDir()) { + final String tmpDir = System.getProperty("java.io.tmpdir"); + if (StringUtil.isNotBlank(tmpDir)) { + ownTmpDir = new File(tmpDir, "fessTmpDir_" + sessionId); + if (ownTmpDir.mkdirs()) { + suggestCreaterCmdList.add("-Djava.io.tmpdir=" + ownTmpDir.getAbsolutePath()); + } else { + ownTmpDir = null; + } + } + } + + suggestCreaterCmdList.add(SuggestCreater.class.getCanonicalName()); + + suggestCreaterCmdList.add("--sessionId"); + suggestCreaterCmdList.add(sessionId); + + final File baseDir = new File(servletContext.getRealPath("/WEB-INF")).getParentFile(); + + if (logger.isInfoEnabled()) { + logger.info("SuggestCreater: \nDirectory=" + baseDir + "\nOptions=" + suggestCreaterCmdList); + } + + final ProcessBuilder pb = new ProcessBuilder(suggestCreaterCmdList); + pb.directory(baseDir); + pb.redirectErrorStream(true); + + try { + final JobProcess jobProcess = jobHelper.startCrawlerProcess(sessionId, pb); + + final InputStreamThread it = jobProcess.getInputStreamThread(); + it.start(); + + final Process currentProcess = jobProcess.getProcess(); + currentProcess.waitFor(); + it.join(5000); + + final int exitValue = currentProcess.exitValue(); + + if (logger.isInfoEnabled()) { + logger.info("SuggestCreater: Exit Code=" + exitValue + " - SuggestCreater Process Output:\n" + it.getOutput()); + } + if (exitValue != 0) { + throw new FessSystemException("Exit Code: " + exitValue + "\nOutput:\n" + it.getOutput()); + } + } catch (final FessSystemException e) { + throw e; + } catch (final InterruptedException e) { + logger.warn("SuggestCreater Process interrupted."); + } catch (final Exception e) { + throw new FessSystemException("SuggestCreater Process terminated.", e); + } finally { + try { + jobHelper.destroyCrawlerProcess(sessionId); + } finally { + deleteTempDir(ownTmpDir); + } + } + } + + private void addSystemProperty(final List crawlerCmdList, final String name, final String defaultValue, final String appendValue) { + final String value = System.getProperty(name); + if (value != null) { + final StringBuilder buf = new StringBuilder(); + buf.append("-D").append(name).append("=").append(value); + if (appendValue != null) { + buf.append(appendValue); + } + crawlerCmdList.add(buf.toString()); + } else if (defaultValue != null) { + crawlerCmdList.add("-D" + name + "=" + defaultValue); + } + } + + protected void deleteTempDir(final File ownTmpDir) { + if (ownTmpDir == null) { + return; + } + for (int i = 0; i < retryCountToDeleteTempDir; i++) { + if (ownTmpDir.delete()) { + return; + } + try { + Thread.sleep(retryIntervalToDeleteTempDir); + } catch (final InterruptedException e) { + // ignore + } + } + logger.warn("Could not delete a temp dir: " + ownTmpDir.getAbsolutePath()); + } + + protected void appendJarFile(final String cpSeparator, final StringBuilder buf, final File libDir, final String basePath) { + final File[] jarFiles = libDir.listFiles((FilenameFilter) (dir, name) -> name.toLowerCase().endsWith(".jar")); + if (jarFiles != null) { + for (final File file : jarFiles) { + buf.append(cpSeparator); + buf.append(basePath); + buf.append(file.getName()); + } + } + } +} diff --git a/src/main/resources/fess.xml b/src/main/resources/fess.xml index 88025bebd..a55ae93de 100644 --- a/src/main/resources/fess.xml +++ b/src/main/resources/fess.xml @@ -139,8 +139,6 @@ "," --> - diff --git a/src/main/resources/fess_indices/.fess_config/scheduled_job.bulk b/src/main/resources/fess_indices/.fess_config/scheduled_job.bulk index 187b55a00..07c272e47 100644 --- a/src/main/resources/fess_indices/.fess_config/scheduled_job.bulk +++ b/src/main/resources/fess_indices/.fess_config/scheduled_job.bulk @@ -1,8 +1,10 @@ {"index":{"_index":".fess_config","_type":"scheduled_job","_id":"1"}} {"name":"Crawler","target":"all","cronExpression":"0 0 0 * * ?","scriptType":"groovy","scriptData":"return container.getComponent(\"crawlJob\").execute(executor);","jobLogging":true,"crawler":true,"available":true,"sortOrder":0,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0} {"index":{"_index":".fess_config","_type":"scheduled_job","_id":"2"}} -{"name":"Minutely Tasks","target":"all","cronExpression":"0 * * * * ?","scriptType":"groovy","scriptData":"return container.getComponent(\"aggregateLogJob\").execute();","jobLogging":false,"crawler":false,"available":true,"sortOrder":0,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0} +{"name":"Suggest","target":"all","cronExpression":"0 0 0 * * ?","scriptType":"groovy","scriptData":"return container.getComponent(\"suggestJob\").execute(executor);","jobLogging":true,"crawler":false,"available":true,"sortOrder":0,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0} {"index":{"_index":".fess_config","_type":"scheduled_job","_id":"3"}} -{"name":"Hourly Tasks","target":"all","cronExpression":"0 0 * * * ?","scriptType":"groovy","scriptData":"return container.getComponent(\"updateHotWordJob\").execute();","jobLogging":false,"crawler":false,"available":true,"sortOrder":0,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0} +{"name":"Minutely Tasks","target":"all","cronExpression":"0 * * * * ?","scriptType":"groovy","scriptData":"return container.getComponent(\"aggregateLogJob\").execute();","jobLogging":false,"crawler":false,"available":true,"sortOrder":0,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0} {"index":{"_index":".fess_config","_type":"scheduled_job","_id":"4"}} +{"name":"Hourly Tasks","target":"all","cronExpression":"0 0 * * * ?","scriptType":"groovy","scriptData":"return container.getComponent(\"updateHotWordJob\").execute();","jobLogging":false,"crawler":false,"available":true,"sortOrder":0,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0} +{"index":{"_index":".fess_config","_type":"scheduled_job","_id":"5"}} {"name":"Daily Tasks","target":"all","cronExpression":"0 0 0 * * ?","scriptType":"groovy","scriptData":"return container.getComponent(\"purgeLogJob\").execute();","jobLogging":false,"crawler":false,"available":true,"sortOrder":0,"createdBy":"system","createdTime":0,"updatedBy":"system","updatedTime":0} diff --git a/src/main/resources/fess_job.xml b/src/main/resources/fess_job.xml index 9adae234f..bc61b15a2 100644 --- a/src/main/resources/fess_job.xml +++ b/src/main/resources/fess_job.xml @@ -10,6 +10,8 @@ + + diff --git a/src/main/webapp/WEB-INF/suggest/resources/app.xml b/src/main/webapp/WEB-INF/suggest/resources/app.xml index 6e7d0a54f..41baec3a6 100644 --- a/src/main/webapp/WEB-INF/suggest/resources/app.xml +++ b/src/main/webapp/WEB-INF/suggest/resources/app.xml @@ -5,86 +5,8 @@ - - - - - - - - - - - - - - - - - - - - - - - "text/html" - "html" - - - "application/msword" - "word" - - - "application/vnd.openxmlformats-officedocument.wordprocessingml.document" - "word" - - - "application/vnd.ms-excel" - "excel" - - - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" - "excel" - - - "application/vnd.ms-powerpoint" - "powerpoint" - - - "application/vnd.openxmlformats-officedocument.presentationml.presentation" - "powerpoint" - - - "application/pdf" - "pdf" - - - + diff --git a/src/main/webapp/js/index.js b/src/main/webapp/js/index.js index 2767f035c..0d7da3f76 100644 --- a/src/main/webapp/js/index.js +++ b/src/main/webapp/js/index.js @@ -21,7 +21,7 @@ $(function(){ $('#contentQuery').suggestor( { ajaxinfo: { url: contextPath + '/suggest', - fn: '_default', + fn: '_default,content,title', num: 10 }, boxCssInfo: { diff --git a/src/main/webapp/js/search.js b/src/main/webapp/js/search.js index 592fd18c0..394d5f045 100644 --- a/src/main/webapp/js/search.js +++ b/src/main/webapp/js/search.js @@ -66,7 +66,7 @@ $(function(){ } $screenshot.children().remove(); - + var content = '' $screenshot.append(content); @@ -100,7 +100,7 @@ $(function(){ queryId: $queryId.val() } }).done(function ( data ) { - if(data.response.status === 0 + if(data.response.status === 0 && typeof data.response.result !== 'undefined' && data.response.result === 'ok'){ var $favorited = $favorite.siblings('.favorited'); @@ -129,7 +129,7 @@ $(function(){ queryId: $queryId.val() } }).done(function ( data ) { - if(data.response.status === 0 + if(data.response.status === 0 && typeof data.response.num !== 'undefined' && data.response.num > 0){ var docIds = data.response.docIds; @@ -174,7 +174,7 @@ $(function(){ $('#query').suggestor( { ajaxinfo: { url: contextPath + '/suggest', - fn: '_default', + fn: '_default,content,title', num: 10 }, boxCssInfo: {