许家凯 vor 3 Jahren
Ursprung
Commit
14f535d850
20 geänderte Dateien mit 1339 neuen und 143 gelöschten Zeilen
  1. 3 9
      src/main/java/com/winhc/phoenix/example/controller/SearchController.java
  2. 1 1
      src/main/java/com/winhc/phoenix/example/dao/SearchDao.java
  3. 28 10
      src/main/java/com/winhc/phoenix/example/dao/impl/SearchDaoImpl.java
  4. 11 1
      src/main/java/com/winhc/phoenix/example/enums/CompanyQueryType.java
  5. 1 0
      src/main/java/com/winhc/phoenix/example/enums/EsVersion.java
  6. 1 1
      src/main/java/com/winhc/phoenix/example/service/SearchService.java
  7. 1 1
      src/main/java/com/winhc/phoenix/example/service/impl/FindRelationshipService.java
  8. 60 43
      src/main/java/com/winhc/phoenix/example/service/impl/SearchV8FastServiceImpl.java
  9. 5 3
      src/main/java/com/winhc/phoenix/example/service/impl/SearchV8ServiceImpl.java
  10. 82 0
      src/main/java/com/winhc/phoenix/example/service/impl/SearchV9ServiceImpl.java
  11. 9 0
      src/main/java/com/winhc/phoenix/example/util/QueryIntentRecognitionType.java
  12. 27 0
      src/main/java/com/winhc/phoenix/example/util/QueryIntentRecognitionUtils.java
  13. 37 0
      src/main/java/com/winhc/phoenix/example/util/company/search/CompanyQueryVo.java
  14. 199 0
      src/main/java/com/winhc/phoenix/example/util/company/search/CompanySearchQueryUtils.java
  15. 43 0
      src/main/resources/application-dev.yml
  16. 60 0
      src/main/resources/application-prod.yml
  17. 1 74
      src/main/resources/application.yml
  18. 381 0
      src/main/resources/static/dynamic/debug-dynamic.html
  19. 43 0
      src/main/resources/static/dynamic/list.html
  20. 346 0
      src/main/resources/static/search-company.html

+ 3 - 9
src/main/java/com/winhc/phoenix/example/controller/SearchController.java

@@ -11,7 +11,6 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
@@ -21,7 +20,6 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
-import java.util.regex.Pattern;
 
 /**
  * @author: XuJiakai
@@ -41,12 +39,12 @@ public class SearchController {
     @ApiOperation(value = "es搜索")
     @GetMapping("query")
     public Object query(String content
-            , @RequestParam(defaultValue = "v8版_Fast") EsVersion version
+            , @RequestParam(defaultValue = "v9") EsVersion version
             , @RequestParam(defaultValue = "0") int from
             , @RequestParam(defaultValue = "10") int size
             , @RequestParam(defaultValue = "默认排序") CompanySearchSortType sortType
     ) {
-        return map.get(version.getValue()).query(cleanup(content), from, size, new HashSet<>(), sortType);
+        return map.get(version.getValue()).query(content, from, size, new HashSet<>(), sortType);
     }
 
 
@@ -57,7 +55,7 @@ public class SearchController {
         if (set == null) {
             set = Collections.emptySet();
         }
-        return map.get(EsVersion.v8版_Fast.getValue()).query(cleanup(content), from, size, set, CompanySearchSortType.默认排序);
+        return map.get(EsVersion.v8版_Fast.getValue()).query(content, from, size, set, CompanySearchSortType.默认排序);
 //        return findRelationshipService.findRelationship(content, typeList, from, size);
     }
 
@@ -77,9 +75,5 @@ public class SearchController {
     }
 
 
-    private static final Pattern pattern = Pattern.compile("[^\\u4e00-\\u9fa50-9a-zA-Z]");
 
-    private static String cleanup(String val) {
-        return StringUtils.isNotBlank(val) ? pattern.matcher(val).replaceAll("") : "";
-    }
 }

+ 1 - 1
src/main/java/com/winhc/phoenix/example/dao/SearchDao.java

@@ -19,7 +19,7 @@ public interface SearchDao {
 
     Object search(String index, String type, QueryBuilder query, int from, int size);
 
-    Object search(String index, String type, QueryBuilder query, List<RescoreBuilder> rescoreBuilder, SortBuilder sortBuilder, FetchSourceContext fetchSourceContext, int from, int size);
+    Object search(String index, String type, QueryBuilder query, List<RescoreBuilder> rescoreBuilder, SortBuilder sortBuilder, FetchSourceContext fetchSourceContext, int from, int size,String preference);
 
     @SneakyThrows
     Object search(String index, String type, SearchSourceBuilder searchSourceBuilder);

+ 28 - 10
src/main/java/com/winhc/phoenix/example/dao/impl/SearchDaoImpl.java

@@ -7,6 +7,7 @@ import com.winhc.phoenix.example.dao.SearchDao;
 import lombok.AllArgsConstructor;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.http.util.EntityUtils;
 import org.elasticsearch.action.bulk.BulkRequest;
 import org.elasticsearch.action.delete.DeleteRequest;
@@ -61,7 +62,7 @@ public class SearchDaoImpl implements SearchDao {
     @SneakyThrows
     @Override
     public Object search(String index, String type, QueryBuilder query, SortBuilder sortBuilder, FetchSourceContext fetchSourceContext, int from, int size) {
-        return search(index, type, query, null, sortBuilder, fetchSourceContext, from, size);
+        return search(index, type, query, null, sortBuilder, fetchSourceContext, from, size, null);
     }
 
     @Override
@@ -71,18 +72,32 @@ public class SearchDaoImpl implements SearchDao {
 
     @SneakyThrows
     @Override
-    public Object search(String index, String type, QueryBuilder query, List<RescoreBuilder> rescoreBuilder, SortBuilder sortBuilder, FetchSourceContext fetchSourceContext, int from, int size) {
-        HighlightBuilder highlightBuilder = new HighlightBuilder()
+    public Object search(String index, String type, QueryBuilder query, List<RescoreBuilder> rescoreBuilder, SortBuilder sortBuilder, FetchSourceContext fetchSourceContext, int from, int size, String preference) {
+        HighlightBuilder highlightBuilder = new HighlightBuilder().order(HighlightBuilder.Order.SCORE)
                 .preTags("<font class='my-bold'>")
                 .postTags("</font>")
-                .field("cname.value")
-                .field("history_name.value", 1)
+                .field("cname.show")
+                .field("cname.show.keyword")
+                .field("cname.show.pinyin")
+                .field("history_name.show.pinyin")
+                .field("history_name.show")
                 .field("legal_entity_name")
-                .field("holder.name", 1)
-                .field("staff.name", 1)
-                .field("icp", 1)
-                .field("app_info", 1)
-                .field("company_tm", 1)
+                .field("holder_history.name")
+                .field("holder.name")
+                .field("staff.name")
+                .field("staff_history.name")
+                .field("icp")
+                .field("app_info")
+                .field("company_tm")
+                .field("emails")
+                .field("emails.keyword")
+                .field("phones")
+                .field("icp_domain")
+                .field("icp_domain.keyword")
+                .field("reg_number")
+                .field("reg_location")
+                .field("org_number")
+                .field("credit_code")
                 .order("score");
         SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
                 .query(query)
@@ -108,6 +123,9 @@ public class SearchDaoImpl implements SearchDao {
                 .indices(index)
                 .types(type)
                 .source(searchSourceBuilder);
+        if (StringUtils.isNotBlank(preference)) {
+            searchRequest.preference(preference);
+        }
         RestHighLevelClient restHighLevelClient = getRestHighLevelClient(index);
 
         SearchResponse search = restHighLevelClient.search(searchRequest);

+ 11 - 1
src/main/java/com/winhc/phoenix/example/enums/CompanyQueryType.java

@@ -4,6 +4,16 @@ package com.winhc.phoenix.example.enums;
  * @author: XuJiakai
  * 2021/8/3 09:05
  */
+@SuppressWarnings("all")
 public enum CompanyQueryType {
-    NAME, LEGAL_REPRESENTATIVE, HOLDER_OR_STAFF, APP
+    NAME(1), LEGAL_REPRESENTATIVE(2), HOLDER_OR_STAFF(3), APP(4);
+    private Integer val;
+
+    public Integer getVal() {
+        return val;
+    }
+
+    CompanyQueryType(Integer val) {
+        this.val = val;
+    }
 }

+ 1 - 0
src/main/java/com/winhc/phoenix/example/enums/EsVersion.java

@@ -13,6 +13,7 @@ import lombok.Getter;
 public enum EsVersion {
 //    v7版(SearchV7ServiceImpl.index),
 //    v8精简版(SearchV8SimpServiceImpl.index),
+    v9("v9"),
     v8版(SearchV8ServiceImpl.index),
     v8版_Fast("v8_fast");
     private final String value;

+ 1 - 1
src/main/java/com/winhc/phoenix/example/service/SearchService.java

@@ -16,5 +16,5 @@ public interface SearchService {
 
 //    Object query(String s, int from, int size, Set<CompanyQueryType> set);
 
-    Object query(String s, int from, int size, Set<CompanyQueryType> set, CompanySearchSortType sortType);
+    Object query(String content, int from, int size, Set<CompanyQueryType> set, CompanySearchSortType sortType);
 }

+ 1 - 1
src/main/java/com/winhc/phoenix/example/service/impl/FindRelationshipService.java

@@ -59,7 +59,7 @@ public class FindRelationshipService {
                 .windowSize(50)
                 .setScoreMode(QueryRescoreMode.Total);
 
-        Object search = searchDao.search(index, type, boolQuery, Arrays.asList(rescorerBuilder2), null, null, from, size);
+        Object search = searchDao.search(index, type, boolQuery, Arrays.asList(rescorerBuilder2), null, null, from, size,null);
 
         return search;
     }

+ 60 - 43
src/main/java/com/winhc/phoenix/example/service/impl/SearchV8FastServiceImpl.java

@@ -1,9 +1,11 @@
 package com.winhc.phoenix.example.service.impl;
 
+import cn.hutool.crypto.SecureUtil;
 import com.winhc.phoenix.example.dao.SearchDao;
 import com.winhc.phoenix.example.enums.CompanyQueryType;
 import com.winhc.phoenix.example.enums.CompanySearchSortType;
 import com.winhc.phoenix.example.service.SearchService;
+import com.winhc.phoenix.example.util.CompanyNameUtils;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.elasticsearch.index.query.*;
@@ -17,7 +19,6 @@ import org.elasticsearch.search.rescore.RescoreBuilder;
 import org.elasticsearch.search.sort.FieldSortBuilder;
 import org.elasticsearch.search.sort.SortBuilders;
 import org.elasticsearch.search.sort.SortOrder;
-import org.springframework.context.annotation.Primary;
 import org.springframework.stereotype.Service;
 
 import java.util.*;
@@ -30,7 +31,7 @@ import static org.elasticsearch.index.query.QueryBuilders.*;
  * 2020/11/19 14:54
  */
 @Slf4j
-@Primary
+//@Primary
 @Service(value = "v8_fast")
 @AllArgsConstructor
 public class SearchV8FastServiceImpl implements SearchService {
@@ -38,7 +39,7 @@ public class SearchV8FastServiceImpl implements SearchService {
 
     //        public static final String index = "winhc-company-v8";
 //    public static final String index = "winhc-company-v8_3";
-    public static final String index = "winhc-company-v8_4";
+    public static final String index = "winhc-company-v8_5";
     public static final String type = "company";
     private static final String[] includes = new String[]{"cname", "legal_entity*", "estiblish_time", "reg_status_std", "company_type", "province_code", "reg_capital", "logo", "new_cid"};
     private static final FetchSourceContext fetchSourceContext = new FetchSourceContext(true, includes, null);
@@ -73,15 +74,17 @@ public class SearchV8FastServiceImpl implements SearchService {
             put("der", 0.85);
         }};
 
+        //加上名称全匹配分数
         QueryRescorerBuilder rescorerBuilder_0 = new QueryRescorerBuilder(functionScoreQuery(new ScriptScoreFunctionBuilder(new Script(ScriptType.STORED, null, "company-name-term-score", map))))
                 .windowSize(100)
                 .setScoreMode(QueryRescoreMode.Total);
 
+        //乘上权重分
         QueryRescorerBuilder rescorerBuilder = new QueryRescorerBuilder(functionScoreQuery(new ScriptScoreFunctionBuilder(new Script(ScriptType.STORED, null, "company-search-script_v2", map))))
                 .windowSize(100)
                 .setScoreMode(QueryRescoreMode.Multiply);
 
-
+        //加上知产的少量加分
         QueryRescorerBuilder rescorerBuilder2 = new QueryRescorerBuilder(getRescorerBool(content))
                 .windowSize(50)
                 .setScoreMode(QueryRescoreMode.Total);
@@ -94,26 +97,27 @@ public class SearchV8FastServiceImpl implements SearchService {
     public Object query(String content, int from, int size, Set<CompanyQueryType> set, CompanySearchSortType sortType) {
         //召回
         BoolQueryBuilder boolQuery = getBoolQuery(content, set);
+        String preference = SecureUtil.md5(content);
 
         if (sortType == CompanySearchSortType.注册资本_从低到高) {
             FieldSortBuilder order = SortBuilders.fieldSort("reg_capital_amount").order(SortOrder.ASC);
-            Object search = searchDao.search(index, type, boolQuery, null, order, null, from, size);
+            Object search = searchDao.search(index, type, boolQuery, null, order, null, from, size, preference);
             return search;
         } else if (sortType == CompanySearchSortType.注册资本_从高到底) {
             FieldSortBuilder order = SortBuilders.fieldSort("reg_capital_amount").order(SortOrder.DESC);
-            Object search = searchDao.search(index, type, boolQuery, null, order, null, from, size);
+            Object search = searchDao.search(index, type, boolQuery, null, order, null, from, size, preference);
             return search;
         } else if (sortType == CompanySearchSortType.成立日期_从早到晚) {
             FieldSortBuilder order = SortBuilders.fieldSort("estiblish_time").order(SortOrder.ASC);
-            Object search = searchDao.search(index, type, boolQuery, null, order, null, from, size);
+            Object search = searchDao.search(index, type, boolQuery, null, order, null, from, size, preference);
             return search;
         } else if (sortType == CompanySearchSortType.成立日期_从晚到早) {
             FieldSortBuilder order = SortBuilders.fieldSort("estiblish_time").order(SortOrder.DESC);
-            Object search = searchDao.search(index, type, boolQuery, null, order, null, from, size);
+            Object search = searchDao.search(index, type, boolQuery, null, order, null, from, size, preference);
             return search;
         } else {
-            List<RescoreBuilder> reScoreBuilder = getReScoreBuilder(content);
-            Object search = searchDao.search(index, type, boolQuery, reScoreBuilder, null, null, from, size);
+            List<RescoreBuilder> reScoreBuilder = getReScoreBuilder(CompanyNameUtils.cleanup(content));
+            Object search = searchDao.search(index, type, boolQuery, reScoreBuilder, null, null, from, size, preference);
             return search;
         }
     }
@@ -139,48 +143,61 @@ public class SearchV8FastServiceImpl implements SearchService {
     private BoolQueryBuilder getBoolQuery(String content, Set<CompanyQueryType> set) {
         BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
 
-//        boolQuery.should(termQuery("cname.value.keyword", content).boost(1000));
+        String org_content = content;
+        content = CompanyNameUtils.cleanup(content);
+
         if (content.length() > 3) {
             boolQuery.should(termQuery("history_name.value.keyword", content).boost(1000));
+            boolQuery.should(termQuery("org_number", org_content.toUpperCase()).boost(1000));
+            boolQuery.should(termQuery("credit_code", org_content.toUpperCase()).boost(1000));
+            boolQuery.should(termQuery("reg_number", org_content.toUpperCase()).boost(1000));
+            boolQuery.should(termQuery("icp_domain.keyword", org_content).boost(1000));
+            boolQuery.should(termQuery("emails.keyword", org_content).boost(1000));
+            boolQuery.should(termQuery("phones", org_content).boost(1000));
+            boolQuery.should(termQuery("reg_location.keyword", org_content).boost(1000));
         }
 
         boolQuery.should(disMaxQuery()
-                        .add(disMaxQuery()
-                                .add(termQuery("legal_entity_name.keyword", content).boost(10))
-                                .add(termQuery("holder.name.keyword", content).boost(10F))
-                                .add(termQuery("staff.name.keyword", content).boost(5.5F))
-                                .tieBreaker(0.3F)
-                        ).add(disMaxQuery()
-
-                                        .add(matchQuery("legal_entity_name", content).boost(6).minimumShouldMatch("5<95%"))
-//                        .add(matchQuery("holder", content).boost(10).minimumShouldMatch("5<80%"))
-//                        .add(matchQuery("staff", content).boost(6).minimumShouldMatch("5<80%"))
+                .add(disMaxQuery()
+                        .add(termQuery("legal_entity_name.keyword", org_content).boost(10))
+                        .add(termQuery("holder.name.keyword", content).boost(10F))
+                        .add(termQuery("holder_history.name.keyword", content).boost(10F))
+                        .add(termQuery("staff.name.keyword", content).boost(5.5F))
+                        .add(termQuery("staff_history.name.keyword", content).boost(5.5F))
+                        .tieBreaker(0.3F)
+                ).add(disMaxQuery()
 
-//                        .add(matchPhraseQuery("legal_entity_name", content).boost(6).slop(3))
-                                        .add(matchPhraseQuery("holder.name", content).boost(10).slop(3))
-                                        .add(matchPhraseQuery("staff.name", content).boost(6).slop(3))
+                        .add(matchQuery("legal_entity_name", org_content).boost(6).minimumShouldMatch("5<95%"))
+                        .add(matchPhraseQuery("holder.name", content).boost(10).slop(3))
+                        .add(matchPhraseQuery("holder_history.name", content).boost(10).slop(3))
+                        .add(matchPhraseQuery("staff.name", content).boost(6).slop(3))
+                        .add(matchPhraseQuery("staff_history.name", content).boost(6).slop(3))
 
-                                        .tieBreaker(0.3F)
-                        ).tieBreaker(0.3F)
+                        .tieBreaker(0.3F)
+                ).tieBreaker(0.3F)
         );
         boolQuery.should(disMaxQuery()
-                        .add(disMaxQuery()
-                                .add(termQuery("icp.keyword", content).boost(20))
-                                .add(termQuery("app_info.keyword", content).boost(40))
-                                .add(termQuery("company_tm.keyword", content).boost(20))
-                                .tieBreaker(0.4F))
-                        .add(disMaxQuery()
-//                        .add(matchQuery("icp", content).boost(8).minimumShouldMatch("5"))
-//                        .add(matchQuery("app_info", content).boost(19).minimumShouldMatch("5"))
-//                        .add(matchQuery("company_tm", content).boost(7).minimumShouldMatch("5"))
-
-
-                                        .add(matchPhraseQuery("icp", content).boost(8).slop(3))
-                                        .add(matchPhraseQuery("app_info", content).boost(19).slop(3))
-                                        .add(matchPhraseQuery("company_tm", content).boost(7).slop(3))
-
-                                        .tieBreaker(0.3F)
-                        ).tieBreaker(0.4F)
+                .add(disMaxQuery()
+                        .add(termQuery("icp.keyword", org_content).boost(20))
+                        .add(termQuery("app_info.keyword", org_content).boost(40))
+                        .add(termQuery("company_tm.keyword", org_content).boost(20))
+                        .tieBreaker(0.4F))
+                .add(disMaxQuery()
+                        .add(matchPhraseQuery("icp", org_content).boost(8).slop(3))
+                        .add(matchPhraseQuery("app_info", org_content).boost(19).slop(3))
+                        .add(matchPhraseQuery("company_tm", org_content).boost(7).slop(3))
+                        .tieBreaker(0.3F)
+                ).tieBreaker(0.4F)
+        );
+
+
+        boolQuery.should(disMaxQuery()
+                .add(disMaxQuery()
+                        .add(matchQuery("reg_location", content).boost(7).minimumShouldMatch("100%"))
+                        .add(matchQuery("emails", org_content).boost(7).minimumShouldMatch("100%"))
+                        .add(matchQuery("icp_domain", org_content).boost(1000).minimumShouldMatch("100%"))
+                        .tieBreaker(0.3F)
+                ).tieBreaker(0.4F)
         );
 
 

+ 5 - 3
src/main/java/com/winhc/phoenix/example/service/impl/SearchV8ServiceImpl.java

@@ -9,12 +9,14 @@ import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.elasticsearch.common.lucene.search.function.CombineFunction;
 import org.elasticsearch.common.lucene.search.function.FiltersFunctionScoreQuery;
-import org.elasticsearch.index.query.*;
+import org.elasticsearch.index.query.BoolQueryBuilder;
+import org.elasticsearch.index.query.MultiMatchQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
 import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
 import org.elasticsearch.index.query.functionscore.ScriptScoreFunctionBuilder;
 import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
 import org.elasticsearch.search.sort.ScriptSortBuilder;
-import org.springframework.context.annotation.Primary;
 import org.springframework.stereotype.Service;
 
 import java.util.Set;
@@ -27,7 +29,7 @@ import static org.elasticsearch.index.query.QueryBuilders.*;
  * 2020/11/19 14:54
  */
 @Slf4j
-@Primary
+//@Primary
 @Service(value = SearchV8ServiceImpl.index)
 @AllArgsConstructor
 public class SearchV8ServiceImpl implements SearchService {

+ 82 - 0
src/main/java/com/winhc/phoenix/example/service/impl/SearchV9ServiceImpl.java

@@ -0,0 +1,82 @@
+package com.winhc.phoenix.example.service.impl;
+
+import cn.hutool.crypto.SecureUtil;
+import com.winhc.phoenix.example.dao.SearchDao;
+import com.winhc.phoenix.example.enums.CompanyQueryType;
+import com.winhc.phoenix.example.enums.CompanySearchSortType;
+import com.winhc.phoenix.example.service.SearchService;
+import com.winhc.phoenix.example.util.company.search.CompanyQueryVo;
+import com.winhc.phoenix.example.util.company.search.CompanySearchQueryUtils;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.search.rescore.RescoreBuilder;
+import org.elasticsearch.search.sort.FieldSortBuilder;
+import org.elasticsearch.search.sort.SortBuilders;
+import org.elasticsearch.search.sort.SortOrder;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @author: XuJiakai
+ * 2021/11/19 17:08
+ */
+@Slf4j
+@Primary
+@Service(value = "v9")
+@AllArgsConstructor
+public class SearchV9ServiceImpl implements SearchService {
+
+    private SearchDao searchDao;
+    public static final String index = "winhc-company-v9_1";
+    public static final String type = "company";
+
+    @Override
+    public Object tips(String s) {
+        return null;
+    }
+
+    @Override
+    public Object controlGroup(String s) {
+        return null;
+    }
+
+    @Override
+    public Object query(String content, int from, int size, Set<CompanyQueryType> set, CompanySearchSortType sortType) {
+        List<Integer> collect = set.stream().map(CompanyQueryType::getVal).collect(Collectors.toList());
+        CompanyQueryVo companyQueryVo = CompanyQueryVo.builder()
+                .content(content)
+                .searchTypeList(collect)
+                .build();
+
+        //召回
+        QueryBuilder queryBuilder = CompanySearchQueryUtils.getQueryBuilder(companyQueryVo);
+        String preference = SecureUtil.md5(content);
+
+        if (sortType == CompanySearchSortType.注册资本_从低到高) {
+            FieldSortBuilder order = SortBuilders.fieldSort("reg_capital_amount").order(SortOrder.ASC);
+            Object search = searchDao.search(index, type, queryBuilder, null, order, null, from, size, preference);
+            return search;
+        } else if (sortType == CompanySearchSortType.注册资本_从高到底) {
+            FieldSortBuilder order = SortBuilders.fieldSort("reg_capital_amount").order(SortOrder.DESC);
+            Object search = searchDao.search(index, type, queryBuilder, null, order, null, from, size, preference);
+            return search;
+        } else if (sortType == CompanySearchSortType.成立日期_从早到晚) {
+            FieldSortBuilder order = SortBuilders.fieldSort("estiblish_time").order(SortOrder.ASC);
+            Object search = searchDao.search(index, type, queryBuilder, null, order, null, from, size, preference);
+            return search;
+        } else if (sortType == CompanySearchSortType.成立日期_从晚到早) {
+            FieldSortBuilder order = SortBuilders.fieldSort("estiblish_time").order(SortOrder.DESC);
+            Object search = searchDao.search(index, type, queryBuilder, null, order, null, from, size, preference);
+            return search;
+        } else {
+            List<RescoreBuilder> reScoreBuilder = CompanySearchQueryUtils.getReScoreBuilder(companyQueryVo);
+            Object search = searchDao.search(index, type, queryBuilder, reScoreBuilder, null, null, from, size, preference);
+            return search;
+        }
+    }
+}

+ 9 - 0
src/main/java/com/winhc/phoenix/example/util/QueryIntentRecognitionType.java

@@ -0,0 +1,9 @@
+package com.winhc.phoenix.example.util;
+
+/**
+ * @author: XuJiakai
+ * 2021/11/17 17:12
+ */
+public enum QueryIntentRecognitionType {
+    EMAIL;
+}

+ 27 - 0
src/main/java/com/winhc/phoenix/example/util/QueryIntentRecognitionUtils.java

@@ -0,0 +1,27 @@
+package com.winhc.phoenix.example.util;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author: XuJiakai
+ * 2021/11/17 17:12
+ */
+public class QueryIntentRecognitionUtils {
+    public static List<QueryIntentRecognitionType> recognition(String content) {
+        if (isEmail(content)) {
+            return Arrays.asList(QueryIntentRecognitionType.EMAIL);
+        }
+
+        return null;
+    }
+
+    private static final Pattern email = Pattern.compile("[a-z_A-Z0-9\\-.]+@[a-zA-Z0-9\\-]+[.(a-zA-Z0-9\\-)]+");
+
+    private static Boolean isEmail(String content) {
+        Matcher matcher = email.matcher(content);
+        return matcher.matches();
+    }
+}

+ 37 - 0
src/main/java/com/winhc/phoenix/example/util/company/search/CompanyQueryVo.java

@@ -0,0 +1,37 @@
+package com.winhc.phoenix.example.util.company.search;
+
+import lombok.*;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * @author: XuJiakai
+ * 2021/11/19 16:56
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class CompanyQueryVo {
+    private String content;
+
+    /**
+     * 查询类型,1名称。2法人。3股东or高管。4品牌or产品
+     */
+    private List<Integer> searchTypeList;
+
+
+    private static final Pattern pattern = Pattern.compile("[^\\u4e00-\\u9fa50-9a-zA-Z]");
+
+
+    public String getCleanupContent() {
+        return cleanup(content);
+    }
+
+    public static String cleanup(String val) {
+        return StringUtils.isNotBlank(val) ? pattern.matcher(val).replaceAll("") : "";
+    }
+}

+ 199 - 0
src/main/java/com/winhc/phoenix/example/util/company/search/CompanySearchQueryUtils.java

@@ -0,0 +1,199 @@
+package com.winhc.phoenix.example.util.company.search;
+
+import org.elasticsearch.index.query.*;
+import org.elasticsearch.index.query.functionscore.ScriptScoreFunctionBuilder;
+import org.elasticsearch.script.Script;
+import org.elasticsearch.script.ScriptType;
+import org.elasticsearch.search.rescore.QueryRescoreMode;
+import org.elasticsearch.search.rescore.QueryRescorerBuilder;
+import org.elasticsearch.search.rescore.RescoreBuilder;
+
+import java.util.*;
+
+import static org.elasticsearch.index.query.QueryBuilders.*;
+
+/**
+ * @author: XuJiakai
+ * 2021/11/17 17:17
+ */
+public class CompanySearchQueryUtils {
+    public static QueryBuilder getQueryBuilder(CompanyQueryVo companyQueryVo) {
+
+        String content = companyQueryVo.getContent();
+        BoolQueryBuilder boolQuery = getBoolQuery(companyQueryVo);
+
+        //以下为过滤逻辑
+        BoolQueryBuilder returnBoolQuery = boolQuery()
+                .filter(termQuery("deleted", "0"))
+                .filter(rangeQuery("company_score_weight").gt(0.3F))
+                .must(boolQuery);
+
+        Optional<List<Integer>> searchTypeList = Optional.ofNullable(companyQueryVo.getSearchTypeList());
+        if (searchTypeList.isPresent()) {
+            BoolQueryBuilder filter = boolQuery();
+            searchTypeList.get().forEach(i -> {
+                switch (i) {
+                    case 1:
+                        filter.should(getSpanNearQuery("cname.show.standard", content));
+                        filter.should(getSpanNearQuery("history_name.show.standard", content));
+                        break;
+                    case 2:
+                        filter.should(getSpanNearQuery("legal_entity_name.standard", content));
+                        break;
+                    case 3:
+                        filter.should(getSpanNearQuery("holder.name.standard", content));
+                        filter.should(getSpanNearQuery("staff.name.standard", content));
+                        break;
+                    case 4:
+                        filter.should(getSpanNearQuery("app_info.standard", content));
+                        break;
+                    default:
+                        break;
+                }
+            });
+            returnBoolQuery.filter(filter);
+        }
+        return returnBoolQuery;
+    }
+
+    public static List<RescoreBuilder> getReScoreBuilder(CompanyQueryVo companyQueryVo) {
+        String content = companyQueryVo.getCleanupContent();
+
+        Map<String, Object> map = new HashMap<String, Object>(2) {{
+            put("query_content", content);
+            put("der", 0.85);
+        }};
+        List<RescoreBuilder> list = new ArrayList<>();
+
+        //加上名称全匹配分数
+        list.add(new QueryRescorerBuilder(functionScoreQuery(new ScriptScoreFunctionBuilder(new Script(ScriptType.STORED, null, "company-name-term-score_v2", map))))
+                .windowSize(100)
+                .setScoreMode(QueryRescoreMode.Total));
+
+        //乘上权重分
+        list.add(new QueryRescorerBuilder(functionScoreQuery(new ScriptScoreFunctionBuilder(new Script(ScriptType.STORED, null, "company-search-script_v2", map))))
+                .windowSize(100)
+                .setScoreMode(QueryRescoreMode.Multiply));
+
+        //加上知产的少量加分
+        list.add(new QueryRescorerBuilder(getRescorerBool(content))
+                .windowSize(50)
+                .setScoreMode(QueryRescoreMode.Total));
+
+        return list;
+    }
+
+
+    private static BoolQueryBuilder getBoolQuery(CompanyQueryVo companyQueryVo) {
+        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
+        String org_content = companyQueryVo.getContent();
+        String content = CompanyQueryVo.cleanup(companyQueryVo.getContent());
+
+        if (content.length() > 3) {
+            boolQuery.should(disMaxQuery()
+                    .add(termQuery("history_name.show.keyword", org_content))
+                    .add(termQuery("history_name.value", content))
+            );
+
+
+            boolQuery.should(termQuery("org_number", org_content.toUpperCase()).boost(1000));
+            boolQuery.should(termQuery("credit_code", org_content.toUpperCase()).boost(1000));
+            boolQuery.should(termQuery("reg_number", org_content.toUpperCase()).boost(1000));
+            boolQuery.should(termQuery("icp_domain.keyword", org_content).boost(1000));
+            boolQuery.should(termQuery("emails.keyword", org_content).boost(1000));
+            boolQuery.should(termQuery("phones", org_content).boost(1000));
+            boolQuery.should(termQuery("reg_location.keyword", org_content).boost(1000));
+        }
+
+        boolQuery.should(disMaxQuery()
+                .add(disMaxQuery()
+                        .add(termQuery("legal_entity_name.keyword", org_content).boost(10))
+                        .add(termQuery("holder.name.keyword", content).boost(10F))
+                        .add(termQuery("holder_history.name.keyword", content).boost(10F))
+                        .add(termQuery("staff.name.keyword", content).boost(5.5F))
+                        .add(termQuery("staff_history.name.keyword", content).boost(5.5F))
+                        .tieBreaker(0.3F))
+                .add(disMaxQuery()
+                        .add(matchQuery("legal_entity_name", org_content).boost(6).minimumShouldMatch("5<95%"))
+                        .add(matchPhraseQuery("holder.name", content).boost(10).slop(3))
+                        .add(matchPhraseQuery("holder_history.name", content).boost(10).slop(3))
+                        .add(matchPhraseQuery("staff.name", content).boost(6).slop(3))
+                        .add(matchPhraseQuery("staff_history.name", content).boost(6).slop(3))
+                        .tieBreaker(0.3F))
+                .tieBreaker(0.3F)
+        );
+        boolQuery.should(disMaxQuery()
+                .add(disMaxQuery()
+                        .add(termQuery("icp.keyword", org_content).boost(20))
+                        .add(termQuery("app_info.keyword", org_content).boost(40))
+                        .add(termQuery("company_tm.keyword", org_content).boost(20))
+                        .tieBreaker(0.4F))
+                .add(disMaxQuery()
+                        .add(matchPhraseQuery("icp", content).boost(8).slop(3))
+                        .add(matchPhraseQuery("app_info", content).boost(19).slop(3))
+                        .add(matchPhraseQuery("company_tm", org_content).boost(7).slop(1))
+                        .add(matchQuery("reg_location", content).boost(1).minimumShouldMatch("100%"))
+                        .tieBreaker(0.3F))
+                .tieBreaker(0.4F)
+        );
+
+
+        boolQuery.should(disMaxQuery()
+                .add(disMaxQuery()
+                        .add(matchQuery("emails", org_content).boost(7).minimumShouldMatch("100%"))
+                        .add(matchQuery("icp_domain", org_content).boost(1000).minimumShouldMatch("100%"))
+
+                        .tieBreaker(0.3F))
+                .tieBreaker(0.4F)
+        );
+
+
+        boolQuery.should(
+                disMaxQuery()
+                        .add(disMaxQuery()
+                                .add(matchPhraseQuery("cname.show.pinyin", content))
+                                .add(matchPhraseQuery("history_name.show.pinyin", content))
+                        )
+                        .add(multiMatchQuery(content)
+                                .type(MultiMatchQueryBuilder.Type.CROSS_FIELDS)
+                                .minimumShouldMatch("5<90%")
+                                .tieBreaker(0.3F)
+
+                                .field("cname.show", 16)
+                                .field("history_name.show", 12))
+                        .add(multiMatchQuery(content)
+                                .operator(Operator.AND)
+                                .type(MultiMatchQueryBuilder.Type.CROSS_FIELDS)
+                                .tieBreaker(0.3F)
+                                .field("cname.show.standard", 16)
+                                .field("history_name.show.standard", 12))
+
+                        .tieBreaker(0.4F)
+        );
+
+        return boolQuery;
+    }
+
+
+    private static BoolQueryBuilder getRescorerBool(String content) {
+        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
+
+        boolQuery.should(disMaxQuery()
+                .add(matchQuery("icp", content).boost(8))
+                .add(matchQuery("app_info", content).boost(19))
+                .add(matchQuery("company_tm", content).boost(20))
+                .tieBreaker(0.5F)
+        );
+        return boolQuery;
+    }
+
+
+    private static QueryBuilder getSpanNearQuery(String fields, String content) {
+        SpanNearQueryBuilder spanNearQueryBuilder = spanNearQuery(spanTermQuery(fields, content.charAt(0) + ""), 1);
+        for (int i = 1; i < content.length(); i++) {
+            spanNearQueryBuilder.addClause(spanTermQuery(fields, content.charAt(i) + ""));
+        }
+        return spanNearQueryBuilder;
+    }
+
+}

+ 43 - 0
src/main/resources/application-dev.yml

@@ -0,0 +1,43 @@
+spring:
+  datasource:
+    phoenix:
+      server:
+        url: http://hb-uf6m8e1nu4ivp06m5-proxy-phoenix-pub.hbase.rds.aliyuncs.com:8765
+
+  data:
+    mongodb:
+      uri: mongodb://itslaw:itslaw_168@dds-uf6ff5dfd9aef3641601-pub.mongodb.rds.aliyuncs.com:3717,dds-uf6ff5dfd9aef3642555-pub.mongodb.rds.aliyuncs.com:3717/itslaw?replicaSet=mgset-6501997
+es:
+  username: elastic
+  password: elastic_168
+  host: es-cn-oew22t8bw002iferu.public.elasticsearch.aliyuncs.com #es-cn-0pp0r32zf000ipovd.public.elasticsearch.aliyuncs.com
+
+
+winhc:
+  dynamic:
+    elasticsearch:
+      primary: new
+      rest:
+        old:
+          username: elastic
+          password: elastic_168
+          uris: es-cn-0pp0r32zf000ipovd.public.elasticsearch.aliyuncs.com:9200
+        new:
+          username: elastic
+          password: elastic_168
+          uris: es-cn-oew22t8bw002iferu.public.elasticsearch.aliyuncs.com:9200
+
+
+
+
+hbase:
+  config:
+    hbase.zookeeper.quorum: hb-proxy-pub-uf6m8e1nu4ivp06m5-master1-001.hbase.rds.aliyuncs.com:2181,hb-proxy-pub-uf6m8e1nu4ivp06m5-master2-001.hbase.rds.aliyuncs.com:2181,hb-proxy-pub-uf6m8e1nu4ivp06m5-master3-001.hbase.rds.aliyuncs.com:2181
+    hbase.client.scanner.timeout.period: 120000
+    hbase.client.retries.number: 5
+    hbase.client.pause: 1000
+    hbase.client.max.perserver.tasks: 10
+    hbase.client.max.perregion.tasks: 10
+    hbase.client.keyvalue.maxsize: 524288000
+    hbase.client.ipc.pool.size: 5
+    zookeeper.recovery.retry: 5

+ 60 - 0
src/main/resources/application-prod.yml

@@ -0,0 +1,60 @@
+spring:
+
+  datasource:
+    phoenix:
+      server:
+        url: http://hb-uf6m8e1nu4ivp06m5-proxy-phoenix.hbase.rds.aliyuncs.com:8765
+  data:
+    mongodb:
+      uri: mongodb://itslaw:itslaw_168@dds-uf6ff5dfd9aef3641.mongodb.rds.aliyuncs.com:3717,dds-uf6ff5dfd9aef3642.mongodb.rds.aliyuncs.com:3717/itslaw?replicaSet=mgset-6501997
+
+  kafka:
+    bootstrap-servers: 192.168.4.237:9092,192.168.4.235:9092,192.168.4.236:9092
+    producer:
+      retries: 3
+      batch-size: 16384
+      buffer-memory: 33554432
+      key-serializer: org.apache.kafka.common.serialization.StringSerializer
+      value-serializer: org.apache.kafka.common.serialization.StringSerializer
+      # acks=0 : 生产者在成功写入消息之前不会等待任何来自服务器的响应。
+      # acks=1 : 只要集群的首领节点收到消息,生产者就会收到一个来自服务器成功响应。
+      # acks=all :只有当所有参与复制的节点全部收到消息时,生产者才会收到一个来自服务器的成功响应。
+      acks: 1
+    consumer:
+      # 该属性指定了消费者在读取一个没有偏移量的分区或者偏移量无效的情况下该作何处理:
+      # latest(默认值)在偏移量无效的情况下,消费者将从最新的记录开始读取数据(在消费者启动之后生成的记录)
+      # earliest :在偏移量无效的情况下,消费者将从起始位置读取分区的记录
+      auto-offset-reset: earliest
+      enable-auto-commit: false
+      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
+      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
+      group-id: phoenix_example_group_id
+      max-poll-records: 1
+      auto-commit-interval: 1000
+    listener:
+      # 在侦听器容器中运行的线程数。
+      concurrency: 1
+
+winhc:
+  dynamic:
+    elasticsearch:
+      primary: new
+      rest:
+        old:
+          username: elastic
+          password: elastic_168
+          uris: es-cn-0pp0r32zf000ipovd.elasticsearch.aliyuncs.com:9200
+        new:
+          username: elastic
+          password: elastic_168
+          uris: es-cn-oew22t8bw002iferu.elasticsearch.aliyuncs.com:9200
+
+
+es:
+  username: elastic
+  password: elastic_168
+  host: es-cn-oew22t8bw002iferu.elasticsearch.aliyuncs.com #es-cn-0pp0r32zf000ipovd.elasticsearch.aliyuncs.com
+
+hbase:
+  config:
+    hbase.zookeeper.quorum: hb-uf6m8e1nu4ivp06m5-master1-001.hbase.rds.aliyuncs.com:2181,hb-uf6m8e1nu4ivp06m5-master2-001.hbase.rds.aliyuncs.com:2181,hb-uf6m8e1nu4ivp06m5-master3-001.hbase.rds.aliyuncs.com:2181

+ 1 - 74
src/main/resources/application.yml

@@ -1,6 +1,6 @@
 spring:
   profiles:
-    active: local
+    active: ${SPRING_PROFILES_ACTIVE:prod}
   jackson:
     date-format: yyyy-MM-dd HH:mm:ss
     time-zone: GMT+8
@@ -13,76 +13,3 @@ odps:
   access-key-secret: r6gWoySXC8kSK4qnfKRxEuWJ5uHIiE
   region-id: cn-shanghai
   ding-secret: SECe7b26876f443e77f872b8b10880e39b3c5dfaf44855f1aa3235372bb73698ab6
----
-spring:
-  profiles: local
-  datasource:
-    phoenix:
-      server:
-        url: http://hb-uf6m8e1nu4ivp06m5-proxy-phoenix-pub.hbase.rds.aliyuncs.com:8765
-
-  data:
-    mongodb:
-      uri: mongodb://itslaw:itslaw_168@dds-uf6ff5dfd9aef3641601-pub.mongodb.rds.aliyuncs.com:3717,dds-uf6ff5dfd9aef3642555-pub.mongodb.rds.aliyuncs.com:3717/itslaw?replicaSet=mgset-6501997
-es:
-  username: elastic
-  password: elastic_168
-  host: es-cn-oew22t8bw002iferu.public.elasticsearch.aliyuncs.com #es-cn-0pp0r32zf000ipovd.public.elasticsearch.aliyuncs.com
-
-hbase:
-  config:
-    hbase.zookeeper.quorum: hb-proxy-pub-uf6m8e1nu4ivp06m5-master1-001.hbase.rds.aliyuncs.com:2181,hb-proxy-pub-uf6m8e1nu4ivp06m5-master2-001.hbase.rds.aliyuncs.com:2181,hb-proxy-pub-uf6m8e1nu4ivp06m5-master3-001.hbase.rds.aliyuncs.com:2181
-    hbase.client.scanner.timeout.period: 120000
-    hbase.client.retries.number: 5
-    hbase.client.pause: 1000
-    hbase.client.max.perserver.tasks: 10
-    hbase.client.max.perregion.tasks: 10
-    hbase.client.keyvalue.maxsize: 524288000
-    hbase.client.ipc.pool.size: 5
-    zookeeper.recovery.retry: 5
----
-spring:
-  profiles: prod
-  datasource:
-    phoenix:
-      server:
-        url: http://hb-uf6m8e1nu4ivp06m5-proxy-phoenix.hbase.rds.aliyuncs.com:8765
-  data:
-    mongodb:
-      uri: mongodb://itslaw:itslaw_168@dds-uf6ff5dfd9aef3641.mongodb.rds.aliyuncs.com:3717,dds-uf6ff5dfd9aef3642.mongodb.rds.aliyuncs.com:3717/itslaw?replicaSet=mgset-6501997
-
-  kafka:
-    bootstrap-servers: 192.168.4.237:9092,192.168.4.235:9092,192.168.4.236:9092
-    producer:
-      retries: 3
-      batch-size: 16384
-      buffer-memory: 33554432
-      key-serializer: org.apache.kafka.common.serialization.StringSerializer
-      value-serializer: org.apache.kafka.common.serialization.StringSerializer
-      # acks=0 : 生产者在成功写入消息之前不会等待任何来自服务器的响应。
-      # acks=1 : 只要集群的首领节点收到消息,生产者就会收到一个来自服务器成功响应。
-      # acks=all :只有当所有参与复制的节点全部收到消息时,生产者才会收到一个来自服务器的成功响应。
-      acks: 1
-    consumer:
-      # 该属性指定了消费者在读取一个没有偏移量的分区或者偏移量无效的情况下该作何处理:
-      # latest(默认值)在偏移量无效的情况下,消费者将从最新的记录开始读取数据(在消费者启动之后生成的记录)
-      # earliest :在偏移量无效的情况下,消费者将从起始位置读取分区的记录
-      auto-offset-reset: earliest
-      enable-auto-commit: false
-      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
-      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
-      group-id: phoenix_example_group_id
-      max-poll-records: 1
-      auto-commit-interval: 1000
-    listener:
-      # 在侦听器容器中运行的线程数。
-      concurrency: 1
-
-es:
-  username: elastic
-  password: elastic_168
-  host: es-cn-oew22t8bw002iferu.elasticsearch.aliyuncs.com #es-cn-0pp0r32zf000ipovd.elasticsearch.aliyuncs.com
-
-hbase:
-  config:
-    hbase.zookeeper.quorum: hb-uf6m8e1nu4ivp06m5-master1-001.hbase.rds.aliyuncs.com:2181,hb-uf6m8e1nu4ivp06m5-master2-001.hbase.rds.aliyuncs.com:2181,hb-uf6m8e1nu4ivp06m5-master3-001.hbase.rds.aliyuncs.com:2181

+ 381 - 0
src/main/resources/static/dynamic/debug-dynamic.html

@@ -0,0 +1,381 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8"/>
+    <title>动态数据测试</title>
+    <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css">
+    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap-table/1.15.4/bootstrap-table.min.css">
+    <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
+    <script src="http://cdn.bootcss.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>
+    <script src="https://cdn.bootcss.com/bootstrap-table/1.15.4/bootstrap-table.min.js"></script>
+    <script src="https://cdn.bootcss.com/bootstrap-table/1.15.4/locale/bootstrap-table-zh-CN.min.js"></script>
+    <script src="https://cdn.jsdelivr.net/npm/js-base64@3.6.1/base64.min.js"></script>
+</head>
+<body>
+
+<div id="search">
+    <div id="search-wrap">
+        <select id="search-select" class="search-choise">
+
+        </select>
+        <input id="search-content" class="search-content" type="text" placeholder="输入搜索内容" name="word">
+        <button class="search-btn" type="submit" onclick="search()">查询</button>
+    </div>
+</div>
+
+
+<br>
+<!--<button class="btn btn-primary" data-toggle="modal" data-target="#myModal">button</button>-->
+
+
+<div id="model">
+
+</div>
+<br>
+<table id="search-result" class="table table-hover"></table>
+<script>
+    let flag = false;
+    let t = new Date().getTime()
+
+    $.get("list.html?"+t, function (result) {
+        // console.log(result);
+        let html = result.split('\n').map(function (value, index, array) {
+            console.log(value)
+            if(!value)
+                return '';
+            let v = value.split(',')
+            return '<option value="' + v[0] + '">' + v[1] + '</option>'
+        }).join('')
+        $("#search-select").html(html);
+    });
+
+
+    function init() {
+        $('#search-result').bootstrapTable({
+            method: 'get',
+            url: "/dynamic/debug", // 请求路径
+            striped: true, // 是否显示行间隔色
+            pageNumber: 1, // 初始化加载第一页
+            pagination: true, // 是否分页
+            sidePagination: 'server', // server:服务器端分页|client:前端分页
+            pageSize: 10, // 单页记录数
+            pageList: [10, 20, 30],
+            /* onClickRow: function (row, value, r, index) {
+                 console.log("click :")
+                 record_click(row.record, row, index)
+             },*/
+            queryParams: function (params) { // 上传服务器的参数
+                var temp = {
+                    code: $("#search-select").val(),
+                    size: params.limit,
+                    from: params.offset,
+                };
+                console.log(temp)
+                return temp;
+            },
+            onLoadSuccess: function () {  //加载成功时执行
+                // alert("加载数据成功");
+            },
+            onLoadError: function () {  //加载失败时执行
+                alert("加载数据失败");
+            },
+            responseHandler: function (res) {
+                console.log(res.hits.hits)
+                var rows = res.hits.hits.map(function (value, index, array) {
+                    value._source.id = value._id
+                    return {
+                        "id": value._id,
+                        "company_name": value._source.association_entity_info.map(function (v, i, a) {
+                            return v.name
+                        }).join(','),
+                        "dynamic_code": value._source.dynamic_code,
+                        "tn": value._source.tn,
+                        "dynamic_info": value._source.dynamic_info,
+                        "rowkey": value._source.rowkey,
+                        // "legal_entity_name": value._source.legal_entity_name,
+                        // "company_score_weight": value._source.company_score_weight,
+                        // "score": value._score,
+                        // "record": value._source,
+                        // "highlight": value.highlight,
+                    };
+                })
+                console.log(rows)
+                return {                            //return bootstrap-table能处理的数据格式
+                    "total": res.hits.total,
+                    "rows": rows
+                }
+            },
+            columns: [
+                {
+                    title: 'id',
+                    field: 'id',
+                    visible: false
+                },
+                {
+                    title: 'id',
+                    field: 'id',
+
+                },
+                {
+                    title: '公司名称',
+                    field: 'company_name',
+                },
+                {
+                    title: 'rowkey',
+                    field: 'rowkey',
+                },
+                {
+                    title: 'dynamic_code',
+                    field: 'dynamic_code',
+                },
+                {
+                    title: 'dynamic_info',
+                    field: 'dynamic_info',
+                    cellStyle: formatTableUnit,
+                    formatter: paramsMatter,
+                    // formatter: highlight
+                },
+                {
+                    title: 'tn',
+                    field: 'tn',
+                },
+                // {
+                //     title: 'company_score_weight',
+                //     field: 'company_score_weight',
+                // },
+                // {
+                //     title: '排序分',
+                //     field: 'score',
+                // }
+
+                /*, {
+                    title: '性别',
+                    field: 'sex',
+                    formatter: formatSex
+                }, {
+                    title: '证件号码',
+                    cellStyle: formatTableUnit,
+                    formatter: paramsMatter,
+                    field: 'card'
+                }, {
+                    title: '联系电话',
+                    field: 'phone'
+                }, {
+                    title: '被访姓名',
+                    field: 'viewPeople'
+                }, {
+                    title: '来访事由',
+                    field: 'viewReason',
+                    formatter: formatReason
+                }, {
+                    title: '来访时间',
+                    field: 'visitTime',
+
+                    formatter: formatTime
+                }, {
+                    title: '是否离开',
+                    field: 'isLeave',
+                    formatter: formatIsLeave
+                }, {
+                    title: '操作',
+                    field: 'id',
+                    formatter: option
+                }*/
+                /*, {
+                    title: '操作',
+                    field: 'record',
+                    formatter: option
+                }*/
+
+            ]
+        })
+        flag = true
+    }
+
+
+    $("#search").keypress(function (event) {
+        if (event.which === 13) {
+            search();
+        }
+    })
+
+    function highlight(value, row, index) {
+        let m = {
+            "cname.value": "名称",
+            "history_name.value": "曾用名",
+            "legal_entity_name": "法人",
+            "holder.name": "股东",
+            "staff.name": "主要成员",
+            "company_tm": "商标",
+            "app_info": "专利",
+            "icp": "ICP",
+        }
+        if (!value) {
+            return '';
+        }
+        console.log(value)
+        let htm =
+            '<div class="row my-label">'
+
+        for (let mKey in m) {
+            if (value[mKey]) {
+                let s = value[mKey].map(function (v, i, a) {
+                    return '<span class="my-badge">' + v + '</span>'
+                }).join(',')
+                htm += '<p>' + m[mKey] + ':' + s + '</p>'
+            }
+        }
+        htm += '</div>'
+        return htm;
+    }
+
+    // 定义删除、更新按钮
+    function option(value, row, index) {
+        var name = value.cname.show
+        var keyNo = value.company_id
+        var no = value.company_id
+
+        var p = 'https://www.winhc.cn/searchCompany/' + Base64.encodeURI(name) + "?n=" + (keyNo ? Base64.encodeURI(keyNo) : "") + "&no=" + Base64.encodeURI(no);
+        return '<button class="btn btn-primary btn-lg" onclick="javascript:window.open(\'' + p + '\')">详情</button>';
+    }
+
+    function search() {
+        if (!flag) {
+            console.info('init...')
+            init()
+        } else {
+            console.info('search...')
+            $('#search-result').bootstrapTable('refresh', {pageSize: 10, pageNumber: 1});
+        }
+    }
+
+    //表格超出宽度鼠标悬停显示td内容
+    function paramsMatter(value, row, index) {
+        var span = document.createElement("span");
+        // var str = JSON.stringify(value, null, "\t");
+        span.setAttribute("title", value);
+        span.innerHTML = value;
+        return span.outerHTML;
+    }
+
+    //td宽度以及内容超过宽度隐藏
+    function formatTableUnit(value, row, index) {
+        return {
+            css: {
+                "white-space": "nowrap",
+                "text-overflow": "ellipsis",
+                "overflow": "hidden",
+                "max-width": "60px"
+            }
+        }
+    }
+
+
+    // 格式化时间
+    function formatTime(value, row, index) {
+        var date = new Date();
+        date.setTime(value);
+        var month = date.getMonth() + 1;
+        var hours = date.getHours();
+        if (hours < 10)
+            hours = "0" + hours;
+        var minutes = date.getMinutes();
+        if (minutes < 10)
+            minutes = "0" + minutes;
+        var time = date.getFullYear() + "-" + month + "-" + date.getDate() +
+            " " + hours + ":" + minutes;
+        return time;
+    }
+
+</script>
+
+<style>
+    #search {
+        position: relative;
+        width: 680px;
+        height: 160px;
+        left: 30px;
+        top: 60px;
+        margin: 0 auto;
+    }
+
+    #search-wrap {
+        position: absolute;
+        /* margin-top: -10px; */
+        width: 460px;
+        height: 36px;
+        margin-left: 16px;
+        border-radius: 18px;
+        box-shadow: 0 0 3px rgba(0, 0, 0, .14);
+        background-color: #FFF;
+
+    }
+
+    #search-wrap .search-content {
+        box-shadow: none;
+        border: 0 none;
+        outline: none;
+        font-family: "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", Arial, Helvetica, sans-serif;
+        margin-top: 3px;
+        margin-left: 18px;
+        width: 0px;
+        height: 30px;
+    }
+
+    .my-label {
+        margin-left: 2px;
+    }
+
+    .my-bold {
+        font-weight: bold;
+        color: black;
+    }
+
+    .my-badge {
+        display: inline-block;
+        min-width: 10px;
+        padding: 3px 7px;
+        font-size: 12px;
+        font-weight: 700;
+        line-height: 1;
+        color: #fff;
+        text-align: center;
+        white-space: nowrap;
+        vertical-align: baseline;
+        background-color: #49AF4F;
+        border-radius: 10px;
+    }
+
+    #search-wrap .search-choise {
+        box-shadow: none;
+        border: 0 none;
+        outline: none;
+        margin-left: 18px;
+        font-family: "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", Arial, Helvetica, sans-serif;
+    }
+
+    #search-wrap .search-choise option {
+        box-shadow: none;
+        border: 0 none;
+        outline: none;
+        margin-left: 18px;
+        font-family: "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", Arial, Helvetica, sans-serif;
+    }
+
+    #search-wrap .search-btn {
+        border: 0px;
+        float: right;
+        /* margin: 4px 4px 4px 0; */
+        width: 66px;
+        outline: none;
+        height: 36px;
+        border-radius: 0px 18px 18px 0px;
+        background-color: #49AF4F;
+        color: #FFF;
+        text-align: center;
+        line-height: 28px;
+    }
+</style>
+</body>
+
+</html>

+ 43 - 0
src/main/resources/static/dynamic/list.html

@@ -0,0 +1,43 @@
+101001,公司名称
+101002,注册资本
+101004,注册地址
+101005,经营范围
+101006,公司状态
+110101,法定代表人存量
+101003,法定代表人增量
+101101,股东变化
+101301,主要成员
+201101,抽查检查
+201201,双随机抽查
+201301,融资信息
+201401,行政许可
+201501,购地信息
+201601,地块公示
+201701,土地转让
+201801,知识产权
+301901,经营异常
+302001,法院公告
+302101,开庭公告
+302201,立案信息
+302401,环保处罚
+302501,严重违法
+302601,行政处罚
+302701,送达公告
+302801,税收违法
+302901,司法拍卖
+303001,欠税公告
+303101,破产信息
+303201,简易注销
+303301,失信被执行人
+303401,公示催告
+303501,被执行人
+303601,终本案件
+303701,限制高消费
+303801,限制出境
+303901,股权出质
+304001,股权质押
+304101,股权冻结
+304201,土地抵押
+304301,动产抵押
+304401,裁判文书
+304501,询价评估结果

+ 346 - 0
src/main/resources/static/search-company.html

@@ -0,0 +1,346 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8"/>
+    <title>公司搜索</title>
+    <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css">
+    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap-table/1.15.4/bootstrap-table.min.css">
+    <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
+    <script src="http://cdn.bootcss.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>
+    <script src="https://cdn.bootcss.com/bootstrap-table/1.15.4/bootstrap-table.min.js"></script>
+    <script src="https://cdn.bootcss.com/bootstrap-table/1.15.4/locale/bootstrap-table-zh-CN.min.js"></script>
+    <script src="js/base64.min.js"></script>
+</head>
+<body>
+
+<div id="search">
+    <div id="search-wrap">
+        <!-- <select id="search-select" class="search-choise">
+             <option></option>
+             <option>资源</option>
+         </select>-->
+        <input id="search-content" class="search-content" type="text" placeholder="输入搜索内容" name="word">
+        <button class="search-btn" type="submit" onclick="search()">搜索</button>
+    </div>
+</div>
+
+
+<br>
+<!--<button class="btn btn-primary" data-toggle="modal" data-target="#myModal">button</button>-->
+
+
+<div id="model">
+
+</div>
+<br>
+<table id="search-result" class="table table-hover"></table>
+<script>
+    let flag = false;
+
+    function init() {
+        $('#search-result').bootstrapTable({
+            method: 'get',
+            url: "/es/query", // 请求路径
+            striped: true, // 是否显示行间隔色
+            pageNumber: 1, // 初始化加载第一页
+            pagination: true, // 是否分页
+            sidePagination: 'server', // server:服务器端分页|client:前端分页
+            pageSize: 10, // 单页记录数
+            pageList: [10, 20, 30],
+            /* onClickRow: function (row, value, r, index) {
+                 console.log("click :")
+                 record_click(row.record, row, index)
+             },*/
+            queryParams: function (params) { // 上传服务器的参数
+                var temp = {
+                    content: $("#search-content").val(),
+                    size: params.limit,
+                    from: params.offset,
+                    // version: "v8版_Fast",
+                };
+                console.log(temp)
+                return temp;
+            },
+            onLoadSuccess: function () {  //加载成功时执行
+                // alert("加载数据成功");
+            },
+            onLoadError: function () {  //加载失败时执行
+                alert("加载数据失败");
+            },
+            responseHandler: function (res) {
+                console.log(res.hits.hits)
+                console.log('查询耗时:', res.took)
+                var rows = res.hits.hits.map(function (value, index, array) {
+                    value._source.company_id = value._id
+                    return {
+                        "company_id": value._id,
+                        "company_name": value._source.cname.show,
+                        "company_rank": value._source.company_rank,
+                        "legal_entity_name": value._source.legal_entity_name,
+                        "company_score_weight": value._source.company_score_weight,
+                        "score": value._score,
+                        "record": value._source,
+                        "highlight": value.highlight,
+                    };
+                });
+                $("#model").html('召回数量:' + res.hits.total + "<br/>查询耗时:" + res.took)
+                return {                            //return bootstrap-table能处理的数据格式
+                    "total": res.hits.total,
+                    "rows": rows
+                }
+            },
+            columns: [
+                {
+                    title: 'id',
+                    field: 'company_id',
+                    visible: false
+                },
+                {
+                    title: '公司id',
+                    field: 'company_id',
+
+                },
+                {
+                    title: '公司名称',
+                    field: 'company_name',
+                },
+                {
+                    title: '法定代表人',
+                    field: 'legal_entity_name',
+                },
+                {
+                    title: '来源',
+                    field: 'highlight',
+                    formatter: highlight
+                },
+                {
+                    title: 'company_rank',
+                    field: 'company_rank',
+                },
+                {
+                    title: 'company_score_weight',
+                    field: 'company_score_weight',
+                },
+                {
+                    title: '排序分',
+                    field: 'score',
+                }
+
+
+                , {
+                    title: '操作',
+                    field: 'record',
+                    formatter: option
+                }
+
+            ]
+        })
+        flag = true
+    }
+
+
+    $("#search").keypress(function (event) {
+        if (event.which === 13) {
+            search();
+        }
+    })
+
+    function highlight(value, row, index) {
+        let m = {
+            "cname.value": "名称",
+            "cname.show": "名称",
+            "cname.show.keyword": "名称",
+            "cname.value.pinyin": "名称拼音",
+            "cname.show.pinyin": "名称拼音",
+            "history_name.value": "曾用名",
+            "history_name.show": "曾用名",
+            "history_name.value.pinyin": "曾用名拼音",
+            "history_name.show.pinyin": "曾用名拼音",
+            "legal_entity_name": "法人",
+            "holder.name": "股东",
+            "holder_history.name": "历史股东",
+            "staff.name": "主要成员",
+            "staff_history.name": "历史主要成员",
+            "company_tm": "商标",
+            "app_info": "产品",
+            "icp": "ICP",
+            "icp_domain": "网址",
+            "icp_domain.keyword": "网址",
+            "emails": "邮箱",
+            "emails.keyword": "邮箱",
+            "phones": "电话",
+            "reg_number": "工商注册号",
+            "reg_location": "注册地址",
+            "reg_location.keyword": "注册地址",
+            "org_number": "组织机构代码",
+            "credit_code": "统一信用代码",
+        }
+        if (!value) {
+            return '';
+        }
+        let htm =
+            '<div class="row my-label">'
+
+        for (let mKey in m) {
+            if (value[mKey]) {
+                let s = value[mKey].map(function (v, i, a) {
+                    v = v.replaceAll("</font>)<font class='my-bold'>", ")").replaceAll("</font>(<font class='my-bold'>", "(")
+                    return '<span class="my-badge">' + v + '</span>'
+                }).join(',')
+                htm += '<p>' + m[mKey] + ':' + s + '</p>'
+            }
+        }
+        htm += '</div>'
+        return htm;
+    }
+
+    // 定义删除、更新按钮
+    function option(value, row, index) {
+        var name = value.cname.show
+        var keyNo = value.company_id
+        var no = value.company_id
+
+        var p = 'https://www.winhc.cn/searchCompany/' + Base64.encodeURI(name) + "?n=" + (keyNo ? Base64.encodeURI(keyNo) : "") + "&no=" + Base64.encodeURI(no);
+        return '<button class="btn btn-primary btn-lg" onclick="javascript:window.open(\'' + p + '\')">详情</button>';
+    }
+
+    function search() {
+        if (!flag) {
+            console.info('init...')
+            init()
+        } else {
+            console.info('search...')
+            $('#search-result').bootstrapTable('refresh', {pageSize: 10, pageNumber: 1});
+        }
+    }
+
+    //表格超出宽度鼠标悬停显示td内容
+    function paramsMatter(value, row, index) {
+        var span = document.createElement("span");
+        var str = JSON.stringify(value, null, "\t");
+        span.setAttribute("title", value.cname.show);
+        span.innerHTML = str;
+        return span.outerHTML;
+    }
+
+    //td宽度以及内容超过宽度隐藏
+    function formatTableUnit(value, row, index) {
+        return {
+            css: {
+                "white-space": "nowrap",
+                "text-overflow": "ellipsis",
+                "overflow": "hidden",
+                "max-width": "60px"
+            }
+        }
+    }
+
+
+    // 格式化时间
+    function formatTime(value, row, index) {
+        var date = new Date();
+        date.setTime(value);
+        var month = date.getMonth() + 1;
+        var hours = date.getHours();
+        if (hours < 10)
+            hours = "0" + hours;
+        var minutes = date.getMinutes();
+        if (minutes < 10)
+            minutes = "0" + minutes;
+        var time = date.getFullYear() + "-" + month + "-" + date.getDate() +
+            " " + hours + ":" + minutes;
+        return time;
+    }
+
+</script>
+
+<style>
+    #search {
+        position: relative;
+        width: 680px;
+        height: 160px;
+        left: 30px;
+        top: 60px;
+        margin: 0 auto;
+    }
+
+    #search-wrap {
+        position: absolute;
+        /* margin-top: -10px; */
+        width: 460px;
+        height: 36px;
+        margin-left: 16px;
+        border-radius: 18px;
+        box-shadow: 0 0 3px rgba(0, 0, 0, .14);
+        background-color: #FFF;
+
+    }
+
+    #search-wrap .search-content {
+        box-shadow: none;
+        border: 0 none;
+        outline: none;
+        font-family: "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", Arial, Helvetica, sans-serif;
+        margin-top: 3px;
+        margin-left: 18px;
+        width: 298px;
+        height: 30px;
+    }
+
+    .my-label {
+        margin-left: 2px;
+    }
+
+    .my-bold {
+        font-weight: bold;
+        color: black;
+    }
+
+    .my-badge {
+        display: inline-block;
+        min-width: 10px;
+        padding: 3px 7px;
+        font-size: 12px;
+        font-weight: 700;
+        line-height: 1;
+        color: #fff;
+        text-align: center;
+        white-space: nowrap;
+        vertical-align: baseline;
+        background-color: #49AF4F;
+        border-radius: 10px;
+    }
+
+    #search-wrap .search-choise {
+        box-shadow: none;
+        border: 0 none;
+        outline: none;
+        margin-left: 18px;
+        font-family: "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", Arial, Helvetica, sans-serif;
+    }
+
+    #search-wrap .search-choise option {
+        box-shadow: none;
+        border: 0 none;
+        outline: none;
+        margin-left: 18px;
+        font-family: "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", Arial, Helvetica, sans-serif;
+    }
+
+    #search-wrap .search-btn {
+        border: 0px;
+        float: right;
+        /* margin: 4px 4px 4px 0; */
+        width: 66px;
+        outline: none;
+        height: 36px;
+        border-radius: 0px 18px 18px 0px;
+        background-color: #49AF4F;
+        color: #FFF;
+        text-align: center;
+        line-height: 28px;
+    }
+</style>
+</body>
+
+</html>