浏览代码

fix #1279 multiple related content

Shinsuke Sugaya 7 年之前
父节点
当前提交
2ba17a7bf1

+ 3 - 0
src/main/config/es/fess_config.json

@@ -899,6 +899,9 @@
           "content" : {
             "type": "keyword"
           },
+          "sortOrder" : {
+            "type": "integer"
+          },
           "virtualHost" : {
             "type": "keyword"
           }

+ 3 - 5
src/main/java/org/codelibs/fess/api/json/JsonApiManager.java

@@ -204,11 +204,9 @@ public class JsonApiManager extends BaseJsonApiManager {
                 buf.append(",\"related_query\":");
                 buf.append(escapeJson(relatedQueries));
             }
-            final String relatedContent = relatedContentHelper.getRelatedContent(params.getQuery());
-            if (StringUtil.isNotBlank(relatedContent)) {
-                buf.append(",\"related_content\":");
-                buf.append(escapeJson(relatedContent));
-            }
+            final String[] relatedContents = relatedContentHelper.getRelatedContents(params.getQuery());
+            buf.append(",\"related_contents\":");
+            buf.append(escapeJson(relatedContents));
             if (!documentItems.isEmpty()) {
                 buf.append(',');
                 buf.append("\"result\":[");

+ 8 - 0
src/main/java/org/codelibs/fess/app/web/admin/relatedcontent/CreateForm.java

@@ -15,6 +15,8 @@
  */
 package org.codelibs.fess.app.web.admin.relatedcontent;
 
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
 import javax.validation.constraints.Size;
 
 import org.codelibs.fess.app.web.CrudMode;
@@ -38,6 +40,11 @@ public class CreateForm {
     @Size(max = 1000)
     public String virtualHost;
 
+    @Min(value = 0)
+    @Max(value = 2147483647)
+    @ValidateTypeFailure
+    public Integer sortOrder;
+
     @Size(max = 1000)
     public String createdBy;
 
@@ -48,5 +55,6 @@ public class CreateForm {
         crudMode = CrudMode.CREATE;
         createdBy = ComponentUtil.getSystemHelper().getUsername();
         createdTime = ComponentUtil.getSystemHelper().getCurrentTimeAsLong();
+        sortOrder = 1;
     }
 }

+ 2 - 4
src/main/java/org/codelibs/fess/app/web/search/SearchAction.java

@@ -138,10 +138,8 @@ public class SearchAction extends FessSearchAction {
                         RenderDataUtil.register(data, "displayQuery",
                                 getDisplayQuery(form, labelTypeHelper.getLabelTypeItemList(SearchRequestType.SEARCH)));
                         createPagingQuery(form);
-                        final String relatedContent = relatedContentHelper.getRelatedContent(form.getQuery());
-                        if (StringUtil.isNotBlank(relatedContent)) {
-                            RenderDataUtil.register(data, "relatedContent", relatedContent);
-                        }
+                        final String[] relatedContents = relatedContentHelper.getRelatedContents(form.getQuery());
+                        RenderDataUtil.register(data, "relatedContents", relatedContents);
                         final String[] relatedQueries = relatedQueryHelper.getRelatedQueries(form.getQuery());
                         if (relatedQueries.length > 0) {
                             RenderDataUtil.register(data, "relatedQueries", relatedQueries);

+ 1 - 0
src/main/java/org/codelibs/fess/es/config/bsbhv/BsRelatedContentBhv.java

@@ -79,6 +79,7 @@ public abstract class BsRelatedContentBhv extends EsAbstractBehavior<RelatedCont
             result.setUpdatedTime(DfTypeUtil.toLong(source.get("updatedTime")));
             result.setTerm(DfTypeUtil.toString(source.get("term")));
             result.setContent(DfTypeUtil.toString(source.get("content")));
+            result.setSortOrder(DfTypeUtil.toInteger(source.get("sortOrder")));
             result.setVirtualHost(DfTypeUtil.toString(source.get("virtualHost")));
             return updateEntity(source, result);
         } catch (InstantiationException | IllegalAccessException e) {

+ 17 - 0
src/main/java/org/codelibs/fess/es/config/bsentity/BsRelatedContent.java

@@ -55,6 +55,9 @@ public class BsRelatedContent extends EsAbstractEntity {
     /** content */
     protected String content;
 
+    /** sortOrder */
+    protected Integer sortOrder;
+
     /** virtualHost */
     protected String virtualHost;
 
@@ -97,6 +100,9 @@ public class BsRelatedContent extends EsAbstractEntity {
         if (content != null) {
             addFieldToSource(sourceMap, "content", content);
         }
+        if (sortOrder != null) {
+            addFieldToSource(sourceMap, "sortOrder", sortOrder);
+        }
         if (virtualHost != null) {
             addFieldToSource(sourceMap, "virtualHost", virtualHost);
         }
@@ -119,6 +125,7 @@ public class BsRelatedContent extends EsAbstractEntity {
         sb.append(dm).append(updatedTime);
         sb.append(dm).append(term);
         sb.append(dm).append(content);
+        sb.append(dm).append(sortOrder);
         sb.append(dm).append(virtualHost);
         if (sb.length() > dm.length()) {
             sb.delete(0, dm.length());
@@ -190,6 +197,16 @@ public class BsRelatedContent extends EsAbstractEntity {
         this.content = value;
     }
 
+    public Integer getSortOrder() {
+        checkSpecifiedProperty("sortOrder");
+        return sortOrder;
+    }
+
+    public void setSortOrder(Integer value) {
+        registerModifiedProperty("sortOrder");
+        this.sortOrder = value;
+    }
+
     public String getVirtualHost() {
         checkSpecifiedProperty("virtualHost");
         return convertEmptyToNull(virtualHost);

+ 9 - 0
src/main/java/org/codelibs/fess/es/config/bsentity/dbmeta/RelatedContentDbm.java

@@ -90,6 +90,8 @@ public class RelatedContentDbm extends AbstractDBMeta {
         setupEpg(_epgMap, et -> ((RelatedContent) et).getTerm(), (et, vl) -> ((RelatedContent) et).setTerm(DfTypeUtil.toString(vl)), "term");
         setupEpg(_epgMap, et -> ((RelatedContent) et).getContent(), (et, vl) -> ((RelatedContent) et).setContent(DfTypeUtil.toString(vl)),
                 "content");
+        setupEpg(_epgMap, et -> ((RelatedContent) et).getSortOrder(),
+                (et, vl) -> ((RelatedContent) et).setSortOrder(DfTypeUtil.toInteger(vl)), "sortOrder");
         setupEpg(_epgMap, et -> ((RelatedContent) et).getVirtualHost(),
                 (et, vl) -> ((RelatedContent) et).setVirtualHost(DfTypeUtil.toString(vl)), "virtualHost");
     }
@@ -140,6 +142,8 @@ public class RelatedContentDbm extends AbstractDBMeta {
             0, null, null, false, null, null, null, null, null, false);
     protected final ColumnInfo _columnContent = cci("content", "content", null, null, String.class, "content", null, false, false, false,
             "keyword", 0, 0, null, null, false, null, null, null, null, null, false);
+    protected final ColumnInfo _columnSortOrder = cci("sortOrder", "sortOrder", null, null, Integer.class, "sortOrder", null, false, false,
+            false, "Integer", 0, 0, null, null, false, null, null, null, null, null, false);
     protected final ColumnInfo _columnVirtualHost = cci("virtualHost", "virtualHost", null, null, String.class, "virtualHost", null, false,
             false, false, "keyword", 0, 0, null, null, false, null, null, null, null, null, false);
 
@@ -167,6 +171,10 @@ public class RelatedContentDbm extends AbstractDBMeta {
         return _columnContent;
     }
 
+    public ColumnInfo columnSortOrder() {
+        return _columnSortOrder;
+    }
+
     public ColumnInfo columnVirtualHost() {
         return _columnVirtualHost;
     }
@@ -179,6 +187,7 @@ public class RelatedContentDbm extends AbstractDBMeta {
         ls.add(columnUpdatedTime());
         ls.add(columnTerm());
         ls.add(columnContent());
+        ls.add(columnSortOrder());
         ls.add(columnVirtualHost());
         return ls;
     }

+ 4 - 0
src/main/java/org/codelibs/fess/es/config/cbean/bs/BsRelatedContentCB.java

@@ -200,6 +200,10 @@ public class BsRelatedContentCB extends EsAbstractConditionBean {
             doColumn("content");
         }
 
+        public void columnSortOrder() {
+            doColumn("sortOrder");
+        }
+
         public void columnVirtualHost() {
             doColumn("virtualHost");
         }

+ 226 - 0
src/main/java/org/codelibs/fess/es/config/cbean/ca/bs/BsRelatedContentCA.java

@@ -1082,6 +1082,232 @@ public abstract class BsRelatedContentCA extends EsAbstractConditionAggregation
         }
     }
 
+    public void setSortOrder_Avg() {
+        setSortOrder_Avg(null);
+    }
+
+    public void setSortOrder_Avg(ConditionOptionCall<AvgAggregationBuilder> opLambda) {
+        setSortOrder_Avg("sortOrder", opLambda);
+    }
+
+    public void setSortOrder_Avg(String name, ConditionOptionCall<AvgAggregationBuilder> opLambda) {
+        AvgAggregationBuilder builder = regAvgA(name, "sortOrder");
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_Max() {
+        setSortOrder_Max(null);
+    }
+
+    public void setSortOrder_Max(ConditionOptionCall<MaxAggregationBuilder> opLambda) {
+        setSortOrder_Max("sortOrder", opLambda);
+    }
+
+    public void setSortOrder_Max(String name, ConditionOptionCall<MaxAggregationBuilder> opLambda) {
+        MaxAggregationBuilder builder = regMaxA(name, "sortOrder");
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_Min() {
+        setSortOrder_Min(null);
+    }
+
+    public void setSortOrder_Min(ConditionOptionCall<MinAggregationBuilder> opLambda) {
+        setSortOrder_Min("sortOrder", opLambda);
+    }
+
+    public void setSortOrder_Min(String name, ConditionOptionCall<MinAggregationBuilder> opLambda) {
+        MinAggregationBuilder builder = regMinA(name, "sortOrder");
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_Sum() {
+        setSortOrder_Sum(null);
+    }
+
+    public void setSortOrder_Sum(ConditionOptionCall<SumAggregationBuilder> opLambda) {
+        setSortOrder_Sum("sortOrder", opLambda);
+    }
+
+    public void setSortOrder_Sum(String name, ConditionOptionCall<SumAggregationBuilder> opLambda) {
+        SumAggregationBuilder builder = regSumA(name, "sortOrder");
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_ExtendedStats() {
+        setSortOrder_ExtendedStats(null);
+    }
+
+    public void setSortOrder_ExtendedStats(ConditionOptionCall<ExtendedStatsAggregationBuilder> opLambda) {
+        setSortOrder_ExtendedStats("sortOrder", opLambda);
+    }
+
+    public void setSortOrder_ExtendedStats(String name, ConditionOptionCall<ExtendedStatsAggregationBuilder> opLambda) {
+        ExtendedStatsAggregationBuilder builder = regExtendedStatsA(name, "sortOrder");
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_Stats() {
+        setSortOrder_Stats(null);
+    }
+
+    public void setSortOrder_Stats(ConditionOptionCall<StatsAggregationBuilder> opLambda) {
+        setSortOrder_Stats("sortOrder", opLambda);
+    }
+
+    public void setSortOrder_Stats(String name, ConditionOptionCall<StatsAggregationBuilder> opLambda) {
+        StatsAggregationBuilder builder = regStatsA(name, "sortOrder");
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_Percentiles() {
+        setSortOrder_Percentiles(null);
+    }
+
+    public void setSortOrder_Percentiles(ConditionOptionCall<PercentilesAggregationBuilder> opLambda) {
+        setSortOrder_Percentiles("sortOrder", opLambda);
+    }
+
+    public void setSortOrder_Percentiles(String name, ConditionOptionCall<PercentilesAggregationBuilder> opLambda) {
+        PercentilesAggregationBuilder builder = regPercentilesA(name, "sortOrder");
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_PercentileRanks() {
+        setSortOrder_PercentileRanks(null);
+    }
+
+    public void setSortOrder_PercentileRanks(ConditionOptionCall<PercentileRanksAggregationBuilder> opLambda) {
+        setSortOrder_PercentileRanks("sortOrder", opLambda);
+    }
+
+    public void setSortOrder_PercentileRanks(String name, ConditionOptionCall<PercentileRanksAggregationBuilder> opLambda) {
+        PercentileRanksAggregationBuilder builder = regPercentileRanksA(name, "sortOrder");
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_Histogram() {
+        setSortOrder_Histogram(null);
+    }
+
+    public void setSortOrder_Histogram(ConditionOptionCall<HistogramAggregationBuilder> opLambda) {
+        setSortOrder_Histogram("sortOrder", opLambda, null);
+    }
+
+    public void setSortOrder_Histogram(ConditionOptionCall<HistogramAggregationBuilder> opLambda,
+            OperatorCall<BsRelatedContentCA> aggsLambda) {
+        setSortOrder_Histogram("sortOrder", opLambda, aggsLambda);
+    }
+
+    public void setSortOrder_Histogram(String name, ConditionOptionCall<HistogramAggregationBuilder> opLambda,
+            OperatorCall<BsRelatedContentCA> aggsLambda) {
+        HistogramAggregationBuilder builder = regHistogramA(name, "sortOrder");
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+        if (aggsLambda != null) {
+            RelatedContentCA ca = new RelatedContentCA();
+            aggsLambda.callback(ca);
+            ca.getAggregationBuilderList().forEach(builder::subAggregation);
+        }
+    }
+
+    public void setSortOrder_Range() {
+        setSortOrder_Range(null);
+    }
+
+    public void setSortOrder_Range(ConditionOptionCall<RangeAggregationBuilder> opLambda) {
+        setSortOrder_Range("sortOrder", opLambda, null);
+    }
+
+    public void setSortOrder_Range(ConditionOptionCall<RangeAggregationBuilder> opLambda, OperatorCall<BsRelatedContentCA> aggsLambda) {
+        setSortOrder_Range("sortOrder", opLambda, aggsLambda);
+    }
+
+    public void setSortOrder_Range(String name, ConditionOptionCall<RangeAggregationBuilder> opLambda,
+            OperatorCall<BsRelatedContentCA> aggsLambda) {
+        RangeAggregationBuilder builder = regRangeA(name, "sortOrder");
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+        if (aggsLambda != null) {
+            RelatedContentCA ca = new RelatedContentCA();
+            aggsLambda.callback(ca);
+            ca.getAggregationBuilderList().forEach(builder::subAggregation);
+        }
+    }
+
+    public void setSortOrder_Count() {
+        setSortOrder_Count(null);
+    }
+
+    public void setSortOrder_Count(ConditionOptionCall<ValueCountAggregationBuilder> opLambda) {
+        setSortOrder_Count("sortOrder", opLambda);
+    }
+
+    public void setSortOrder_Count(String name, ConditionOptionCall<ValueCountAggregationBuilder> opLambda) {
+        ValueCountAggregationBuilder builder = regCountA(name, "sortOrder");
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_Cardinality() {
+        setSortOrder_Cardinality(null);
+    }
+
+    public void setSortOrder_Cardinality(ConditionOptionCall<CardinalityAggregationBuilder> opLambda) {
+        setSortOrder_Cardinality("sortOrder", opLambda);
+    }
+
+    public void setSortOrder_Cardinality(String name, ConditionOptionCall<CardinalityAggregationBuilder> opLambda) {
+        CardinalityAggregationBuilder builder = regCardinalityA(name, "sortOrder");
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_Missing() {
+        setSortOrder_Missing(null);
+    }
+
+    public void setSortOrder_Missing(ConditionOptionCall<MissingAggregationBuilder> opLambda) {
+        setSortOrder_Missing("sortOrder", opLambda, null);
+    }
+
+    public void setSortOrder_Missing(ConditionOptionCall<MissingAggregationBuilder> opLambda, OperatorCall<BsRelatedContentCA> aggsLambda) {
+        setSortOrder_Missing("sortOrder", opLambda, aggsLambda);
+    }
+
+    public void setSortOrder_Missing(String name, ConditionOptionCall<MissingAggregationBuilder> opLambda,
+            OperatorCall<BsRelatedContentCA> aggsLambda) {
+        MissingAggregationBuilder builder = regMissingA(name, "sortOrder");
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+        if (aggsLambda != null) {
+            RelatedContentCA ca = new RelatedContentCA();
+            aggsLambda.callback(ca);
+            ca.getAggregationBuilderList().forEach(builder::subAggregation);
+        }
+    }
+
     public void setVirtualHost_Terms() {
         setVirtualHost_Terms(null);
     }

+ 178 - 0
src/main/java/org/codelibs/fess/es/config/cbean/cq/bs/BsRelatedContentCQ.java

@@ -1430,6 +1430,184 @@ public abstract class BsRelatedContentCQ extends EsAbstractConditionQuery {
         return this;
     }
 
+    public void setSortOrder_Equal(Integer sortOrder) {
+        setSortOrder_Term(sortOrder, null);
+    }
+
+    public void setSortOrder_Equal(Integer sortOrder, ConditionOptionCall<TermQueryBuilder> opLambda) {
+        setSortOrder_Term(sortOrder, opLambda);
+    }
+
+    public void setSortOrder_Term(Integer sortOrder) {
+        setSortOrder_Term(sortOrder, null);
+    }
+
+    public void setSortOrder_Term(Integer sortOrder, ConditionOptionCall<TermQueryBuilder> opLambda) {
+        TermQueryBuilder builder = regTermQ("sortOrder", sortOrder);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_NotEqual(Integer sortOrder) {
+        setSortOrder_NotTerm(sortOrder, null);
+    }
+
+    public void setSortOrder_NotTerm(Integer sortOrder) {
+        setSortOrder_NotTerm(sortOrder, null);
+    }
+
+    public void setSortOrder_NotEqual(Integer sortOrder, ConditionOptionCall<BoolQueryBuilder> opLambda) {
+        setSortOrder_NotTerm(sortOrder, opLambda);
+    }
+
+    public void setSortOrder_NotTerm(Integer sortOrder, ConditionOptionCall<BoolQueryBuilder> opLambda) {
+        not(not -> not.setSortOrder_Term(sortOrder), opLambda);
+    }
+
+    public void setSortOrder_Terms(Collection<Integer> sortOrderList) {
+        setSortOrder_Terms(sortOrderList, null);
+    }
+
+    public void setSortOrder_Terms(Collection<Integer> sortOrderList, ConditionOptionCall<TermsQueryBuilder> opLambda) {
+        TermsQueryBuilder builder = regTermsQ("sortOrder", sortOrderList);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_InScope(Collection<Integer> sortOrderList) {
+        setSortOrder_Terms(sortOrderList, null);
+    }
+
+    public void setSortOrder_InScope(Collection<Integer> sortOrderList, ConditionOptionCall<TermsQueryBuilder> opLambda) {
+        setSortOrder_Terms(sortOrderList, opLambda);
+    }
+
+    public void setSortOrder_Match(Integer sortOrder) {
+        setSortOrder_Match(sortOrder, null);
+    }
+
+    public void setSortOrder_Match(Integer sortOrder, ConditionOptionCall<MatchQueryBuilder> opLambda) {
+        MatchQueryBuilder builder = regMatchQ("sortOrder", sortOrder);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_MatchPhrase(Integer sortOrder) {
+        setSortOrder_MatchPhrase(sortOrder, null);
+    }
+
+    public void setSortOrder_MatchPhrase(Integer sortOrder, ConditionOptionCall<MatchPhraseQueryBuilder> opLambda) {
+        MatchPhraseQueryBuilder builder = regMatchPhraseQ("sortOrder", sortOrder);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_MatchPhrasePrefix(Integer sortOrder) {
+        setSortOrder_MatchPhrasePrefix(sortOrder, null);
+    }
+
+    public void setSortOrder_MatchPhrasePrefix(Integer sortOrder, ConditionOptionCall<MatchPhrasePrefixQueryBuilder> opLambda) {
+        MatchPhrasePrefixQueryBuilder builder = regMatchPhrasePrefixQ("sortOrder", sortOrder);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_Fuzzy(Integer sortOrder) {
+        setSortOrder_Fuzzy(sortOrder, null);
+    }
+
+    public void setSortOrder_Fuzzy(Integer sortOrder, ConditionOptionCall<MatchQueryBuilder> opLambda) {
+        MatchQueryBuilder builder = regFuzzyQ("sortOrder", sortOrder);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_GreaterThan(Integer sortOrder) {
+        setSortOrder_GreaterThan(sortOrder, null);
+    }
+
+    public void setSortOrder_GreaterThan(Integer sortOrder, ConditionOptionCall<RangeQueryBuilder> opLambda) {
+        final Object _value = sortOrder;
+        RangeQueryBuilder builder = regRangeQ("sortOrder", ConditionKey.CK_GREATER_THAN, _value);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_LessThan(Integer sortOrder) {
+        setSortOrder_LessThan(sortOrder, null);
+    }
+
+    public void setSortOrder_LessThan(Integer sortOrder, ConditionOptionCall<RangeQueryBuilder> opLambda) {
+        final Object _value = sortOrder;
+        RangeQueryBuilder builder = regRangeQ("sortOrder", ConditionKey.CK_LESS_THAN, _value);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_GreaterEqual(Integer sortOrder) {
+        setSortOrder_GreaterEqual(sortOrder, null);
+    }
+
+    public void setSortOrder_GreaterEqual(Integer sortOrder, ConditionOptionCall<RangeQueryBuilder> opLambda) {
+        final Object _value = sortOrder;
+        RangeQueryBuilder builder = regRangeQ("sortOrder", ConditionKey.CK_GREATER_EQUAL, _value);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_LessEqual(Integer sortOrder) {
+        setSortOrder_LessEqual(sortOrder, null);
+    }
+
+    public void setSortOrder_LessEqual(Integer sortOrder, ConditionOptionCall<RangeQueryBuilder> opLambda) {
+        final Object _value = sortOrder;
+        RangeQueryBuilder builder = regRangeQ("sortOrder", ConditionKey.CK_LESS_EQUAL, _value);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_Exists() {
+        setSortOrder_Exists(null);
+    }
+
+    public void setSortOrder_Exists(ConditionOptionCall<ExistsQueryBuilder> opLambda) {
+        ExistsQueryBuilder builder = regExistsQ("sortOrder");
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public void setSortOrder_CommonTerms(Integer sortOrder) {
+        setSortOrder_CommonTerms(sortOrder, null);
+    }
+
+    public void setSortOrder_CommonTerms(Integer sortOrder, ConditionOptionCall<CommonTermsQueryBuilder> opLambda) {
+        CommonTermsQueryBuilder builder = regCommonTermsQ("sortOrder", sortOrder);
+        if (opLambda != null) {
+            opLambda.callback(builder);
+        }
+    }
+
+    public BsRelatedContentCQ addOrderBy_SortOrder_Asc() {
+        regOBA("sortOrder");
+        return this;
+    }
+
+    public BsRelatedContentCQ addOrderBy_SortOrder_Desc() {
+        regOBD("sortOrder");
+        return this;
+    }
+
     public void setVirtualHost_Equal(String virtualHost) {
         setVirtualHost_Term(virtualHost, null);
     }

+ 7 - 4
src/main/java/org/codelibs/fess/helper/RelatedContentHelper.java

@@ -57,6 +57,7 @@ public class RelatedContentHelper {
 
         return ComponentUtil.getComponent(RelatedContentBhv.class).selectList(cb -> {
             cb.query().matchAll();
+            cb.query().addOrderBy_SortOrder_Asc();
             cb.query().addOrderBy_Term_Asc();
             cb.fetchFirst(ComponentUtil.getFessConfig().getPageRelatedqueryMaxFetchSizeAsInteger());
         });
@@ -90,22 +91,24 @@ public class RelatedContentHelper {
         return StringUtil.isBlank(key) ? StringUtil.EMPTY : key;
     }
 
-    public String getRelatedContent(final String query) {
+    public String[] getRelatedContents(final String query) {
         final FessConfig fessConfig = ComponentUtil.getFessConfig();
         final String key = fessConfig.getVirtualHostKey();
         final Pair<Map<String, String>, List<Pair<Pattern, String>>> pair = relatedContentMap.get(key);
         if (pair != null) {
+            final List<String> contentList = new ArrayList<>();
             final String content = pair.getFirst().get(toLowerCase(query));
             if (StringUtil.isNotBlank(content)) {
-                return content;
+                contentList.add(content);
             }
             for (final Pair<Pattern, String> regexData : pair.getSecond()) {
                 if (regexData.getFirst().matcher(query).matches()) {
-                    return regexData.getSecond().replace(queryPlaceHolder, query);
+                    contentList.add(regexData.getSecond().replace(queryPlaceHolder, query));
                 }
             }
+            return contentList.toArray(new String[contentList.size()]);
         }
-        return StringUtil.EMPTY;
+        return StringUtil.EMPTY_STRINGS;
     }
 
     private String toLowerCase(final String term) {

+ 3 - 0
src/main/resources/fess_indices/.fess_config/related_content.json

@@ -16,6 +16,9 @@
       "virtualHost": {
         "type": "keyword"
       },
+      "sortOrder": {
+        "type": "integer"
+      },
       "createdBy": {
         "type": "keyword"
       },

+ 5 - 0
src/main/webapp/WEB-INF/view/admin/relatedcontent/admin_relatedcontent_details.jsp

@@ -59,6 +59,11 @@
 														key="labels.related_content_content" /></th>
 												<td>${f:h(content)}<la:hidden property="content" /></td>
 											</tr>
+											<tr>
+												<th class="col-xs-2"><la:message
+														key="labels.sortOrder" /></th>
+												<td>${f:h(sortOrder)}<la:hidden property="sortOrder" /></td>
+											</tr>
 											<tr>
 												<th class="col-xs-2"><la:message
 														key="labels.virtual_host" /></th>

+ 8 - 0
src/main/webapp/WEB-INF/view/admin/relatedcontent/admin_relatedcontent_edit.jsp

@@ -60,6 +60,14 @@
 											<la:textarea styleId="content" property="content" styleClass="form-control" rows="5"/>
 										</div>
 									</div>
+									<div class="form-group">
+										<label for="sortOrder" class="col-sm-3 control-label"><la:message
+												key="labels.sortOrder" /></label>
+										<div class="col-sm-9">
+											<la:errors property="sortOrder" />
+											<la:text styleId="sortOrder" property="sortOrder" styleClass="form-control" />
+										</div>
+									</div>
 									<div class="form-group">
 										<label for="virtualHost" class="col-sm-3 control-label"><la:message
 												key="labels.virtual_host" /></label>

+ 3 - 3
src/main/webapp/WEB-INF/view/search.jsp

@@ -131,13 +131,13 @@
 				</div>
 			</div>
 		</c:if>
-		<c:if test="${!empty relatedContent}">
+		<c:forEach var="item" varStatus="s" items="${relatedContents}">
 			<div class="row">
 				<div class="col-md-12">
-					${relatedContent}
+					${item}
 				</div>
 			</div>
-		</c:if>
+		</c:forEach>
 		<c:choose>
 			<c:when test="${f:h(allRecordCount) != 0}">
 				<jsp:include page="searchResults.jsp" />