许家凯 2 лет назад
Родитель
Сommit
1541eda243
33 измененных файлов с 1866 добавлено и 147 удалено
  1. 10 4
      pom.xml
  2. 25 21
      src/main/java/com/winhc/phoenix/example/configuration/DynamicElasticSearchClient.java
  3. 19 0
      src/main/java/com/winhc/phoenix/example/configuration/ProjectConfiguration.java
  4. 42 0
      src/main/java/com/winhc/phoenix/example/controller/JudgmentDocumentsController.java
  5. 6 2
      src/main/java/com/winhc/phoenix/example/controller/SearchController.java
  6. 4 2
      src/main/java/com/winhc/phoenix/example/dao/SearchDao.java
  7. 69 30
      src/main/java/com/winhc/phoenix/example/dao/impl/SearchDaoImpl.java
  8. 11 0
      src/main/java/com/winhc/phoenix/example/framework/mongo/MongoDbFastScan.java
  9. 20 0
      src/main/java/com/winhc/phoenix/example/framework/mongo/MongoDbFastScanHandle.java
  10. 17 16
      src/main/java/com/winhc/phoenix/example/job/EsScanJob.java
  11. 117 0
      src/main/java/com/winhc/phoenix/example/job/OdpsDataUploadJob.java
  12. 21 0
      src/main/java/com/winhc/phoenix/example/service/JudgmentDocumentsService.java
  13. 146 0
      src/main/java/com/winhc/phoenix/example/service/impl/JudgmentDocumentsServiceImpl.java
  14. 2 3
      src/main/java/com/winhc/phoenix/example/service/impl/SearchV8FastServiceImpl.java
  15. 3 3
      src/main/java/com/winhc/phoenix/example/service/impl/SearchV9ServiceImpl.java
  16. 23 0
      src/main/java/com/winhc/phoenix/example/util/DateUtils.java
  17. 41 0
      src/main/java/com/winhc/phoenix/example/util/OdpsTableSchemaUtils.java
  18. 79 2
      src/main/java/com/winhc/phoenix/example/util/QueryBuilderUtils.java
  19. 13 2
      src/main/java/com/winhc/phoenix/example/util/company/search/CompanyIndexUtils.java
  20. 37 0
      src/main/java/com/winhc/phoenix/example/util/company/search/CompanySearchClassifyUtils.java
  21. 207 22
      src/main/java/com/winhc/phoenix/example/util/company/search/CompanySearchQueryUtils.java
  22. 94 36
      src/main/java/com/winhc/phoenix/example/util/company/search/CompanySearchTipsUtils.java
  23. 74 0
      src/main/java/com/winhc/phoenix/example/util/company/search/ElasticSearchScriptTest.java
  24. 9 0
      src/main/java/com/winhc/phoenix/example/vo/judgment/CourtLevels.java
  25. 107 0
      src/main/java/com/winhc/phoenix/example/vo/judgment/JudgmentDocumentsSearchContent.java
  26. 71 0
      src/main/java/com/winhc/phoenix/example/vo/judgment/JudgmentDocumentsSearchType.java
  27. 9 0
      src/main/java/com/winhc/phoenix/example/vo/judgment/JudgmentDocumentsSortType.java
  28. 105 0
      src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientConfigurations.java
  29. 7 0
      src/main/resources/application-dev.yml
  30. 5 1
      src/main/resources/application-prod.yml
  31. 8 0
      src/main/resources/static/js/base64.min.js
  32. 43 3
      src/main/resources/static/search-company.html
  33. 422 0
      src/main/resources/static/search-wenshu.html

+ 10 - 4
pom.xml

@@ -33,6 +33,7 @@
         </dependency>-->
 
 
+
         <dependency>
             <groupId>org.elasticsearch</groupId>
             <artifactId>elasticsearch</artifactId>
@@ -210,11 +211,16 @@
             <version>portable-1.8.2</version>
         </dependency>
 
-        <!-- https://mvnrepository.com/artifact/com.github.stuxuhai/jpinyin -->
         <dependency>
-            <groupId>com.github.stuxuhai</groupId>
-            <artifactId>jpinyin</artifactId>
-            <version>1.1.8</version>
+            <groupId>com.github.houbb</groupId>
+            <artifactId>opencc4j</artifactId>
+            <version>1.7.2</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.winhc</groupId>
+            <artifactId>winhc-bigdata-tool</artifactId>
+            <version>1.1.0</version>
         </dependency>
 
 <!--        <dependency>-->

+ 25 - 21
src/main/java/com/winhc/phoenix/example/configuration/DynamicElasticSearchClient.java

@@ -6,10 +6,7 @@ import org.elasticsearch.client.Response;
 import org.elasticsearch.client.RestClient;
 import org.elasticsearch.client.RestHighLevelClient;
 
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -31,22 +28,7 @@ public class DynamicElasticSearchClient {
         this.primary = primary;
         Map<String, Set<String>> tmpIndexMap = restClientMap.entrySet().stream().collect(Collectors.toMap(e -> e.getKey().replace("_client", ""), e -> {
             RestClient restClient = e.getValue();
-            try {
-                Response get = restClient.performRequest("get", "_cat/indices?h=index");
-                String s = EntityUtils.toString(get.getEntity());
-                Set<String> collect = Arrays.stream(s.split("\n")).filter(index -> !index.startsWith(".")).collect(Collectors.toSet());
-
-                Response get2 = restClient.performRequest("get", "_cat/aliases?h=alias");
-                String s2 = EntityUtils.toString(get2.getEntity());
-                Set<String> collect1 = Arrays.stream(s2.split("\n")).filter(index -> !index.startsWith(".")).collect(Collectors.toSet());
-
-                collect1.addAll(collect);
-                return collect1;
-            } catch (Exception ex) {
-                log.error(ex.getMessage(), e.getKey());
-                log.error(ex.getMessage(), ex);
-                throw new RuntimeException(ex);
-            }
+            return getIndexAndAliases(restClient);
         }, (t1, t2) -> t1));
         indexMap = tmpIndexMap.entrySet().stream().flatMap(e -> {
             String client = e.getKey();
@@ -54,6 +36,29 @@ public class DynamicElasticSearchClient {
         }).collect(Collectors.groupingBy(e -> e.split("\001")[0], Collectors.mapping(e -> e.split("\001")[1], Collectors.toList())));
     }
 
+    private Set<String> getIndexAndAliases(RestClient restClient) {
+        HashSet<String> indexSet = new HashSet<>();
+        try {
+            Response get = restClient.performRequest("get", "_cat/indices?h=index");
+            String s = EntityUtils.toString(get.getEntity());
+            Set<String> collect = Arrays.stream(s.split("\n")).filter(index -> !index.startsWith(".")).collect(Collectors.toSet());
+            indexSet.addAll(collect);
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+
+        try {
+            Response get2 = restClient.performRequest("get", "_cat/aliases?h=alias");
+            String s2 = EntityUtils.toString(get2.getEntity());
+            Set<String> collect1 = Arrays.stream(s2.split("\n")).filter(index -> !index.startsWith(".")).collect(Collectors.toSet());
+            indexSet.addAll(collect1);
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+        return indexSet;
+    }
+
+
     public RestClient getRestClient() {
         return getRestClient(primary);
     }
@@ -93,7 +98,6 @@ public class DynamicElasticSearchClient {
             throw new RuntimeException(ds + " not fount !");
         }
         return restClientMap.get(ds + "_client");
-
     }
 
     public RestHighLevelClient getRestHighLevelClient(String ds) {

+ 19 - 0
src/main/java/com/winhc/phoenix/example/configuration/ProjectConfiguration.java

@@ -0,0 +1,19 @@
+package com.winhc.phoenix.example.configuration;
+
+import com.winhc.tool.component.WinhcIpParser;
+import lombok.SneakyThrows;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author: XuJiakai
+ * 2022/8/15 15:57
+ */
+@Configuration
+public class ProjectConfiguration {
+    @SneakyThrows
+    @Bean
+    public WinhcIpParser winhcIpParser() {
+        return new WinhcIpParser();
+    }
+}

+ 42 - 0
src/main/java/com/winhc/phoenix/example/controller/JudgmentDocumentsController.java

@@ -0,0 +1,42 @@
+package com.winhc.phoenix.example.controller;
+
+import cn.hutool.extra.servlet.ServletUtil;
+import com.winhc.phoenix.example.aspect.Timer;
+import com.winhc.phoenix.example.service.JudgmentDocumentsService;
+import com.winhc.phoenix.example.vo.judgment.JudgmentDocumentsSearchContent;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @author: XuJiakai
+ * 2022/7/29 14:38
+ */
+@Slf4j
+@AllArgsConstructor
+@RestController
+@Api(tags = "文书查询", value = "judgment")
+@RequestMapping("judgment")
+public class JudgmentDocumentsController {
+    private HttpServletRequest request;
+
+
+    private final JudgmentDocumentsService judgmentDocumentsService;
+
+    @Timer
+    @ApiOperation(value = "文书查询")
+    @PostMapping("query")
+    public Object query(@RequestBody JudgmentDocumentsSearchContent content) {
+        String clientIP = ServletUtil.getClientIP(request);
+        content.setIp(clientIP);
+        return judgmentDocumentsService.search(content);
+    }
+
+}

+ 6 - 2
src/main/java/com/winhc/phoenix/example/controller/SearchController.java

@@ -44,6 +44,12 @@ public class SearchController {
             , @RequestParam(defaultValue = "10") int size
             , @RequestParam(defaultValue = "默认排序") CompanySearchSortType sortType
     ) {
+        if (content.startsWith("tips:")) {
+            content = content.substring(5);
+            log.info("search tips: {}", content);
+            return map.get(version.getValue()).tips(content);
+        }
+
         return map.get(version.getValue()).query(content, from, size, new HashSet<>(), sortType);
     }
 
@@ -57,7 +63,6 @@ public class SearchController {
     }
 
 
-
     @Timer
     @ApiOperation(value = "找关系搜索")
     @GetMapping("find-relationship")
@@ -85,5 +90,4 @@ public class SearchController {
     }
 
 
-
 }

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

@@ -4,7 +4,7 @@ import lombok.SneakyThrows;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.search.builder.SearchSourceBuilder;
 import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
-import org.elasticsearch.search.rescore.RescoreBuilder;
+import org.elasticsearch.search.rescore.QueryRescorerBuilder;
 import org.elasticsearch.search.sort.SortBuilder;
 
 import java.util.List;
@@ -19,7 +19,9 @@ 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,String preference);
+    Object search(String index, String type, QueryBuilder query, List<QueryRescorerBuilder> rescoreBuilder, SortBuilder sortBuilder, FetchSourceContext fetchSourceContext, int from, int size, String preference);
+
+    Object search(String index, String type, QueryBuilder query, List<QueryRescorerBuilder> rescoreBuilder, List<SortBuilder> sortBuilder, FetchSourceContext fetchSourceContext, int from, int size, String preference,List<String> highlightField);
 
     @SneakyThrows
     Object search(String index, String type, SearchSourceBuilder searchSourceBuilder);

+ 69 - 30
src/main/java/com/winhc/phoenix/example/dao/impl/SearchDaoImpl.java

@@ -20,12 +20,12 @@ import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.search.builder.SearchSourceBuilder;
 import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
 import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
+import org.elasticsearch.search.rescore.QueryRescorerBuilder;
 import org.elasticsearch.search.rescore.RescoreBuilder;
 import org.elasticsearch.search.sort.SortBuilder;
 import org.springframework.stereotype.Repository;
 
-import java.util.HashMap;
-import java.util.List;
+import java.util.*;
 
 /**
  * @author: XuJiakai
@@ -37,8 +37,18 @@ import java.util.List;
 public class SearchDaoImpl implements SearchDao {
     private final DynamicElasticSearchClient dynamicElasticSearchClient;
 
+
+    private final static Set<String> oldEsIndex = new HashSet<String>(
+
+    ) {
+        {
+            add("winhc-company-dynamic-v1");
+            add("wenshu_detail4");
+        }
+    };
+
     private RestClient getRestClient(String index) {
-        if ("winhc-company-dynamic-v1".equals(index)) {
+        if (oldEsIndex.contains(index)) {
             return dynamicElasticSearchClient.getRestClient("old");
         } else {
             return dynamicElasticSearchClient.getRestClient("new");
@@ -46,7 +56,7 @@ public class SearchDaoImpl implements SearchDao {
     }
 
     private RestHighLevelClient getRestHighLevelClient(String index) {
-        if ("winhc-company-dynamic-v1".equals(index)) {
+        if (oldEsIndex.contains(index)) {
             return dynamicElasticSearchClient.getRestHighLevelClient("old");
         } else {
             return dynamicElasticSearchClient.getRestHighLevelClient("new");
@@ -70,35 +80,64 @@ public class SearchDaoImpl implements SearchDao {
         return search(index, type, query, null, null, from, size);
     }
 
+    @Override
+    public Object search(String index, String type, QueryBuilder query, List<QueryRescorerBuilder> rescoreBuilder, SortBuilder sortBuilder, FetchSourceContext fetchSourceContext, int from, int size, String preference) {
+        List<String> list = Arrays.asList(
+                "cname.show",
+                "cname.show.keyword",
+                "name_alias",
+                "cname.show.pinyin",
+                "history_name.show.pinyin",
+                "history_name.show",
+                "legal_entity_name",
+                "holder_history.name",
+                "holder.name",
+                "staff.name",
+                "staff_history.name",
+                "icp",
+                "app_info",
+                "company_tm",
+                "emails",
+                "emails.keyword",
+                "phones",
+                "icp_domain",
+                "icp_domain.keyword",
+                "reg_number",
+                "reg_location",
+                "org_number",
+                "credit_code"
+        );
+        ArrayList<SortBuilder> objects = new ArrayList<>();
+
+
+        if (sortBuilder != null) {
+            objects.add(sortBuilder);
+        }
+        return search(index, type, query, rescoreBuilder, objects, fetchSourceContext, from, size, preference, list);
+    }
+
     @SneakyThrows
     @Override
-    public Object search(String index, String type, QueryBuilder query, List<RescoreBuilder> rescoreBuilder, SortBuilder sortBuilder, FetchSourceContext fetchSourceContext, int from, int size, String preference) {
+    public Object search(String index
+            , String type
+            , QueryBuilder query
+            , List<QueryRescorerBuilder> rescoreBuilder
+            , List<SortBuilder> sortBuilder
+            , FetchSourceContext fetchSourceContext
+            , int from
+            , int size
+            , String preference
+            , List<String> highlightField
+    ) {
+
         HighlightBuilder highlightBuilder = new HighlightBuilder().order(HighlightBuilder.Order.SCORE)
                 .preTags("<font class='my-bold'>")
                 .postTags("</font>")
-                .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_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");
+        if (highlightField != null)
+            for (String f : highlightField) {
+                highlightBuilder.field(f);
+            }
         SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
                 .query(query)
                 .from(from)
@@ -114,9 +153,9 @@ public class SearchDaoImpl implements SearchDao {
             searchSourceBuilder.fetchSource(fetchSourceContext);
         }
         if (sortBuilder != null) {
-            searchSourceBuilder.sort(sortBuilder)
-//                    .trackScores(true)
-            ;
+            for (SortBuilder builder : sortBuilder) {
+                searchSourceBuilder.sort(builder);
+            }
         }
 
         SearchRequest searchRequest = new SearchRequest()

+ 11 - 0
src/main/java/com/winhc/phoenix/example/framework/mongo/MongoDbFastScan.java

@@ -30,6 +30,7 @@ public class MongoDbFastScan {
         this.mongoDatabase = mongoDatabase;
     }
 
+
     public MongoDbFastScan threadNum(int thread_num) {
         this.thread_num = thread_num;
         return this;
@@ -46,18 +47,28 @@ public class MongoDbFastScan {
     }
 
     private void scan(int skip, int limit) {
+        if (func instanceof MongoDbFastScanHandle) {
+            ((MongoDbFastScanHandle) func).init();
+            log.info("start:{} end:{} init success!", skip, skip + limit);
+        }
         List<Document> list = new ArrayList<>();
         for (Document document : mongoDatabase.getCollection(scanTable).find().skip(skip).limit(limit).noCursorTimeout(true).batchSize(batchSize)) {
             list.add(document);
             if (list.size() >= batchSize) {
+                log.info("start:{} end:{} handle ...", skip, skip + limit);
                 func.accept(list);
                 list.clear();
             }
         }
         if (!list.isEmpty()) {
+            log.info("start:{} end:{} handle ...", skip, skip + limit);
             func.accept(list);
             list.clear();
         }
+        if (func instanceof MongoDbFastScanHandle) {
+            ((MongoDbFastScanHandle) func).close();
+            log.info("start:{} end:{} init close!", skip, skip + limit);
+        }
         log.info("start:{} end:{} success", skip, skip + limit);
     }
 

+ 20 - 0
src/main/java/com/winhc/phoenix/example/framework/mongo/MongoDbFastScanHandle.java

@@ -0,0 +1,20 @@
+package com.winhc.phoenix.example.framework.mongo;
+
+import org.bson.Document;
+
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * @author: XuJiakai
+ * 2021/12/20 10:06
+ */
+public interface MongoDbFastScanHandle extends Consumer<List<Document>> {
+    default void init() {
+
+    }
+
+    default void close() {
+
+    }
+}

+ 17 - 16
src/main/java/com/winhc/phoenix/example/job/EsScanJob.java

@@ -3,7 +3,6 @@ package com.winhc.phoenix.example.job;
 import com.mongodb.client.MongoCollection;
 import com.winhc.phoenix.example.configuration.DynamicElasticSearchClient;
 import com.winhc.phoenix.example.framework.es.EsFastScan;
-import com.winhc.phoenix.example.util.DateUtils;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.bson.Document;
@@ -34,17 +33,12 @@ public class EsScanJob {
 
 
     public void fixBugByDeleted(String dsl, String tn) {
-        String ymd = DateUtils.getYesterday_ymd();
-
-        MongoCollection<Document> person = mongoTemplate.getCollection("company_back_update_0423");
+        MongoCollection<Document> person = mongoTemplate.getCollection("a_xjk_hk_deleted_id_20211216");
         Consumer<SearchHit[]> func = list -> {
             List<Document> li = Arrays.stream(list).map(d -> {
                 String id = d.getId();
                 Document document = new Document();
-                // document.put("_id", id);
-                document.put("rowkey", id);
-                document.put("ds", ymd);
-                document.put("tn", tn);
+                document.put("_id", id);
                 return document;
             }).collect(Collectors.toList());
             person.insertMany(li);
@@ -57,14 +51,21 @@ public class EsScanJob {
         String dsl = "{\n" +
                 "  \"query\": {\n" +
                 "    \"bool\": {\n" +
-                "      \"must_not\": [\n" +
-                "        {\"terms\": {\n" +
-                "          \"deleted\": [\n" +
-                "            \"0\",\n" +
-                "             \"9\",\n" +
-                "            \"1\"\n" +
-                "          ]\n" +
-                "        }}\n" +
+                "      \"must\": [\n" +
+                "        {\n" +
+                "          \"term\": {\n" +
+                "            \"company_type\": {\n" +
+                "              \"value\": \"2\"\n" +
+                "            }\n" +
+                "          }\n" +
+                "        },{\n" +
+                "          \"terms\": {\n" +
+                "            \"deleted\": [\n" +
+                "              \"0\",\n" +
+                "              \"1\"\n" +
+                "            ]\n" +
+                "          }\n" +
+                "        }\n" +
                 "      ]\n" +
                 "    }\n" +
                 "  }\n" +

+ 117 - 0
src/main/java/com/winhc/phoenix/example/job/OdpsDataUploadJob.java

@@ -0,0 +1,117 @@
+package com.winhc.phoenix.example.job;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.aliyun.odps.Column;
+import com.aliyun.odps.Odps;
+import com.aliyun.odps.TableSchema;
+import com.aliyun.odps.data.Record;
+import com.aliyun.odps.data.RecordWriter;
+import com.aliyun.odps.tunnel.TableTunnel;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoDatabase;
+import com.winhc.phoenix.example.framework.mongo.MongoDbFastScan;
+import com.winhc.phoenix.example.framework.mongo.MongoDbFastScanHandle;
+import com.winhc.phoenix.example.util.OdpsTableSchemaUtils;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.bson.Document;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * @author: XuJiakai
+ * 2021/12/20 09:16
+ */
+@Slf4j
+@Component
+@AllArgsConstructor
+public class OdpsDataUploadJob {
+    private final Odps odps;
+    private final MongoTemplate mongoTemplate;
+
+    @SneakyThrows
+    public void start() {
+        TableTunnel tableTunnel = new TableTunnel(odps);
+        TableTunnel.UploadSession uploadSession = tableTunnel
+                .createUploadSession("winhc_ng", "xjk_ads_company_hk_upload_20211220", false);
+        TableSchema schema = uploadSession.getSchema();
+
+        Consumer<List<Document>> consumer = new MongoDbFastScanHandle() {
+            private RecordWriter recordWriter;
+            private Record record;
+
+            @SneakyThrows
+            @Override
+            public void init() {
+                recordWriter = uploadSession.openBufferedWriter();
+                record = uploadSession.newRecord();
+            }
+
+            @SneakyThrows
+            @Override
+            public void accept(List<Document> list) {
+                for (Document d : list) {
+                    String s = d.toJson();
+                    try {
+                        JSONObject jsonObject = JSON.parseObject(s);
+                        JSONObject company = jsonObject.getJSONObject("company");
+                        for (Column column : schema.getColumns()) {
+                            String name = column.getName();
+                            Object o = OdpsTableSchemaUtils.json2Value(company, name, name, schema);
+                            record.set(name, o);
+                        }
+                    } catch (Exception e) {
+                        log.info("error data: {}", s);
+                        log.error(e.getMessage(), e);
+                        throw new RuntimeException(e);
+                    }
+                    recordWriter.write(record);
+                }
+            }
+
+            @SneakyThrows
+            @Override
+            public void close() {
+                recordWriter.close();
+            }
+        };
+
+        MongoDatabase db = mongoTemplate.getDb();
+
+        MongoDbFastScan mongoDbFastScan = new MongoDbFastScan("hongkang_company_info1", consumer, db)
+                .batchSize(500).threadNum(1);
+        mongoDbFastScan.scan();
+        uploadSession.commit();
+    }
+
+    @SneakyThrows
+    public void test() {
+        TableTunnel tableTunnel = new TableTunnel(odps);
+        TableTunnel.UploadSession uploadSession = tableTunnel.createUploadSession("winhc_ng", "xjk_ads_company_hk_upload_20211220");
+        TableSchema schema = uploadSession.getSchema();
+        MongoCollection<Document> collection = mongoTemplate.getCollection("hongkang_company_info");
+
+        for (Document d : collection.find().limit(10)) {
+            String s = d.toJson();
+            JSONObject jsonObject = JSON.parseObject(s);
+            JSONObject company = jsonObject.getJSONObject("company");
+            for (Column column : schema.getColumns()) {
+                String name = column.getName();
+                Object o = OdpsTableSchemaUtils.json2Value(company, name, name, schema);
+                if (o == null) {
+                    log.info("{} type : {} ,value : {}", name, column.getTypeInfo().getOdpsType().name(), o);
+                } else {
+                    log.info("{} type : {} ,value : {}", name, o.getClass().getName(), o);
+                }
+            }
+        }
+
+    }
+
+
+}

+ 21 - 0
src/main/java/com/winhc/phoenix/example/service/JudgmentDocumentsService.java

@@ -0,0 +1,21 @@
+package com.winhc.phoenix.example.service;
+
+import com.winhc.phoenix.example.vo.judgment.JudgmentDocumentsSearchContent;
+
+/**
+ * @author: XuJiakai
+ * 2022/7/29 11:38
+ */
+public interface JudgmentDocumentsService {
+
+
+    /**
+     * 搜索
+     *
+     * @param searchContent
+     * @return
+     */
+    Object search(JudgmentDocumentsSearchContent searchContent);
+
+
+}

+ 146 - 0
src/main/java/com/winhc/phoenix/example/service/impl/JudgmentDocumentsServiceImpl.java

@@ -0,0 +1,146 @@
+package com.winhc.phoenix.example.service.impl;
+
+import com.winhc.phoenix.example.dao.SearchDao;
+import com.winhc.phoenix.example.service.JudgmentDocumentsService;
+import com.winhc.phoenix.example.util.company.search.CompanyIndexUtils;
+import com.winhc.phoenix.example.vo.judgment.JudgmentDocumentsSearchContent;
+import com.winhc.phoenix.example.vo.judgment.JudgmentDocumentsSearchType;
+import com.winhc.phoenix.example.vo.judgment.JudgmentDocumentsSortType;
+import com.winhc.tool.bean.IpInfo;
+import com.winhc.tool.component.WinhcIpParser;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.elasticsearch.index.query.BoolQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.script.Script;
+import org.elasticsearch.search.sort.*;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+import static com.winhc.phoenix.example.util.QueryBuilderUtils.existField;
+import static com.winhc.phoenix.example.util.QueryBuilderUtils.spanNearQuery4StandardAnalyzer;
+import static org.elasticsearch.index.query.QueryBuilders.*;
+
+/**
+ * @author: XuJiakai
+ * 2022/7/29 14:19
+ */
+@Slf4j
+@Service
+@AllArgsConstructor
+public class JudgmentDocumentsServiceImpl implements JudgmentDocumentsService {
+    private WinhcIpParser winhcIpParser;
+
+    private SearchDao searchDao;
+    public static final String index = "wenshu_detail4";
+    public static final String type = "wenshu_detail_type";
+
+    private static final List<String> highlightField = new ArrayList<String>() {{
+        add("addenda");
+        add("case_no");
+        add("case_no.keyword");
+        add("clerk");
+        add("court_name");
+        add("court_view");
+        add("fact");
+        add("judge");
+        add("judge_result");
+        add("party_info");
+        add("title");
+    }};
+
+
+    private static void mustOrFilter(boolean must, BoolQueryBuilder boolQuery, QueryBuilder queryBuilder) {
+        if (must) {
+            boolQuery.must(queryBuilder);
+        } else {
+            boolQuery.filter(queryBuilder);
+        }
+    }
+
+    @Override
+    public Object search(JudgmentDocumentsSearchContent searchContent) {
+        BoolQueryBuilder boolQuery = boolQuery();
+        if (searchContent.isAuthorityCase()) {
+            boolQuery.filter(termsQuery("sample_type", "1", "2", "3"));
+        } else {
+            boolQuery.filter(termQuery("sample_type", "9"));
+        }
+
+
+        Map<String, JudgmentDocumentsSearchType> content = searchContent.getContent();
+        for (Map.Entry<String, JudgmentDocumentsSearchType> entry : content.entrySet()) {
+            if (entry.getKey().contains(" ")) {
+                for (String s : entry.getKey().split(" +")) {
+                    if (StringUtils.isEmpty(s)) {
+                        continue;
+                    }
+                    mustOrFilter(searchContent.isNotSort(), boolQuery, getSearchContentQuery(entry.getValue(), s));
+                }
+            } else {
+                mustOrFilter(searchContent.isNotSort(), boolQuery, getSearchContentQuery(entry.getValue(), entry.getKey()));
+            }
+        }
+
+
+        boolQuery.filter(existField("court_level", Arrays.asList("", "-1")));
+
+
+        int from = searchContent.getFrom();
+        int size = searchContent.getSize();
+        String preference = searchContent.getPreference();
+
+
+        JudgmentDocumentsSortType sort = searchContent.getSort();
+        List<SortBuilder> sortBuilders = new ArrayList<>();
+        if (sort == null && !searchContent.isNotSort()) {
+            String ip = searchContent.getIp();
+            IpInfo ipInfo = winhcIpParser.parseIp(ip);
+            if (ipInfo.getIpProvinceCode() != null) {
+                Map<String, Object> map = new HashMap<String, Object>(2);
+                map.put("provinceCode", ipInfo.getIpProvinceCode());
+                map.put("cityCode", ipInfo.getIpCityCode());
+
+                log.info("province: {},city: {}", ipInfo.getIpProvince(), ipInfo.getIpCity());
+
+                Script script = CompanyIndexUtils.getScript("if('0'.equals(doc['court_level'].value)) return 100;" +
+                        "if(params.provinceCode.equals(doc['court_province_code'].value)&&params.cityCode==null) return 100;" +
+                        "if(params.provinceCode.equals(doc['court_province_code'].value)&&params.cityCode!=null && params.cityCode.equals(doc['court_city_code'].value)) return 100;return 0;", map);
+                ScriptSortBuilder order = SortBuilders.scriptSort(script, ScriptSortBuilder.ScriptSortType.NUMBER).order(SortOrder.DESC);
+                sortBuilders.add(order);
+            }
+
+            FieldSortBuilder order = SortBuilders.fieldSort("case_score").order(SortOrder.DESC);
+            sortBuilders.add(order);
+        }
+
+        Object search = searchDao.search(index, type, boolQuery, null, sortBuilders, null, from, size, preference, highlightField);
+        return search;
+    }
+
+
+    private static QueryBuilder getSearchContentQuery(JudgmentDocumentsSearchType searchScope, String content) {
+        BoolQueryBuilder boolQuery = boolQuery();
+        List<String> fields = searchScope.getFields();
+        if (fields == null) {
+            Arrays.stream(JudgmentDocumentsSearchType.values()).map(JudgmentDocumentsSearchType::getFields).filter(Objects::nonNull).flatMap(Collection::stream).forEach(e -> {
+                if (JudgmentDocumentsSearchType.KEYWORD_FIELDS.contains(e)) {
+                    boolQuery.should(termQuery(e, content));
+                } else {
+                    boolQuery.should(spanNearQuery4StandardAnalyzer(e, content));
+                }
+            });
+        } else {
+            for (String e : searchScope.getFields()) {
+                if (JudgmentDocumentsSearchType.KEYWORD_FIELDS.contains(e)) {
+                    boolQuery.should(termQuery(e, content));
+                } else {
+                    boolQuery.should(spanNearQuery4StandardAnalyzer(e, content));
+                }
+            }
+        }
+        return boolQuery;
+    }
+}

+ 2 - 3
src/main/java/com/winhc/phoenix/example/service/impl/SearchV8FastServiceImpl.java

@@ -15,7 +15,6 @@ import org.elasticsearch.script.ScriptType;
 import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
 import org.elasticsearch.search.rescore.QueryRescoreMode;
 import org.elasticsearch.search.rescore.QueryRescorerBuilder;
-import org.elasticsearch.search.rescore.RescoreBuilder;
 import org.elasticsearch.search.sort.FieldSortBuilder;
 import org.elasticsearch.search.sort.SortBuilders;
 import org.elasticsearch.search.sort.SortOrder;
@@ -68,7 +67,7 @@ public class SearchV8FastServiceImpl implements SearchService {
     }
 
 
-    private List<RescoreBuilder> getReScoreBuilder(String content) {
+    private List<QueryRescorerBuilder> getReScoreBuilder(String content) {
         Map<String, Object> map = new HashMap<String, Object>(2) {{
             put("query_content", content);
             put("der", 0.85);
@@ -116,7 +115,7 @@ public class SearchV8FastServiceImpl implements SearchService {
             Object search = searchDao.search(index, type, boolQuery, null, order, null, from, size, preference);
             return search;
         } else {
-            List<RescoreBuilder> reScoreBuilder = getReScoreBuilder(CompanyNameUtils.cleanup(content));
+            List<QueryRescorerBuilder> reScoreBuilder = getReScoreBuilder(CompanyNameUtils.cleanup(content));
             Object search = searchDao.search(index, type, boolQuery, reScoreBuilder, null, null, from, size, preference);
             return search;
         }

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

@@ -34,8 +34,8 @@ import java.util.stream.Collectors;
 public class SearchV9ServiceImpl implements SearchService {
 
     private SearchDao searchDao;
-    public static final String index = "winhc-company-v9_1";
-//    public static final String index = "winhc_index_rt_company";
+//    public static final String index = "winhc-company-v9_2";
+    public static final String index = "winhc_index_rt_company";
     public static final String type = "company";
 
     private static final String[] includesTips = new String[]{"cname", "legal_entity*", "estiblish_time", "reg_status_std", "company_type","logo", "new_cid"};
@@ -47,7 +47,7 @@ public class SearchV9ServiceImpl implements SearchService {
         QueryBuilder tips = CompanySearchTipsUtils.tips(s);
         String preference = SecureUtil.md5(s);
         List<QueryRescorerBuilder> reScoreBuilder = CompanySearchTipsUtils.getReScoreBuilder(s);
-        Object search = searchDao.search(index, type, tips, reScoreBuilder, null, fetchSourceContextTips, 0, 10, preference);
+        Object search = searchDao.search(index, type, tips, reScoreBuilder, null, null, 0, 10, preference);
         return search;
     }
 

+ 23 - 0
src/main/java/com/winhc/phoenix/example/util/DateUtils.java

@@ -1,9 +1,15 @@
 package com.winhc.phoenix.example.util;
 
+
+import lombok.SneakyThrows;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
 import java.time.Instant;
 import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
 import java.time.temporal.ChronoUnit;
+import java.util.Date;
 import java.util.Locale;
 
 /**
@@ -12,6 +18,8 @@ import java.util.Locale;
  * @Description:
  */
 public class DateUtils {
+    private static final ThreadLocal<DateFormat> localDateFormat = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
+
     private static final DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd")
             .withLocale(Locale.CHINA)
             .withZone(ZoneId.systemDefault());
@@ -19,6 +27,10 @@ public class DateUtils {
             .withLocale(Locale.CHINA)
             .withZone(ZoneId.systemDefault());
 
+    private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+            .withLocale(Locale.CHINA)
+            .withZone(ZoneId.systemDefault());
+
     public static String getYesterday() {
         Instant instant = Instant.now().minus(1, ChronoUnit.DAYS);
         return df.format(instant);
@@ -33,4 +45,15 @@ public class DateUtils {
         Instant instant = Instant.now().minus(i, ChronoUnit.DAYS);
         return df.format(instant);
     }
+
+    @SneakyThrows
+    public static Date toDate(String s) {
+        return localDateFormat.get().parse(s);
+    }
+
+
+    public static void main(String[] args) {
+        System.out.println(toDate("2021-12-20 12:21:59"));
+
+    }
 }

+ 41 - 0
src/main/java/com/winhc/phoenix/example/util/OdpsTableSchemaUtils.java

@@ -0,0 +1,41 @@
+package com.winhc.phoenix.example.util;
+
+import com.alibaba.fastjson.JSONPath;
+import com.aliyun.odps.Column;
+import com.aliyun.odps.OdpsType;
+import com.aliyun.odps.TableSchema;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * @author: XuJiakai
+ * 2021/12/20 11:38
+ */
+public class OdpsTableSchemaUtils {
+
+    public static Object json2Value(Object json, String jsonPath, String key, TableSchema schema) {
+        Object o = JSONPath.eval(json, jsonPath);
+        if (o instanceof Integer) {
+            o = o + "";
+        }
+        String eval = ((String) o);
+        if (StringUtils.isBlank(eval)) {
+            return null;
+        }
+        Column column = schema.getColumn(key);
+        OdpsType odpsType = column.getTypeInfo().getOdpsType();
+        switch (odpsType) {
+            case STRING:
+                return ((String) eval);
+            case BIGINT:
+                return Long.parseLong(eval);
+            case DATETIME:
+                try {
+                    return DateUtils.toDate(eval);
+                } catch (Exception e) {
+                    return null;
+                }
+            default:
+                throw new RuntimeException("odps type: " + odpsType.name() + " is not found !");
+        }
+    }
+}

+ 79 - 2
src/main/java/com/winhc/phoenix/example/util/QueryBuilderUtils.java

@@ -2,8 +2,18 @@ package com.winhc.phoenix.example.util;
 
 
 import com.alibaba.fastjson.JSONObject;
-import org.elasticsearch.index.query.QueryBuilders;
-import org.elasticsearch.index.query.WrapperQueryBuilder;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
+import org.elasticsearch.index.query.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.elasticsearch.index.query.QueryBuilders.*;
 
 /**
  * @author XuJiakai
@@ -11,6 +21,7 @@ import org.elasticsearch.index.query.WrapperQueryBuilder;
  * @Description:
  * @date 2019/3/25 13:03
  */
+@Slf4j
 public class QueryBuilderUtils {
     public static final String q = "query";
 
@@ -23,4 +34,70 @@ public class QueryBuilderUtils {
         }
         return QueryBuilders.wrapperQuery(dsl_json);
     }
+
+
+    public 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;
+    }
+
+
+    @SneakyThrows
+    public static QueryBuilder spanNearQuery4StandardAnalyzer(String fields, String content) {
+        try (Analyzer analyzer = new StandardAnalyzer()) {
+            TokenStream stream = analyzer.tokenStream(fields, content);
+            CharTermAttribute cta = stream.addAttribute(CharTermAttribute.class);
+            stream.reset();
+
+            SpanNearQueryBuilder spanNearQueryBuilder = null;
+            while (stream.incrementToken()) {
+                if (spanNearQueryBuilder == null) {
+                    spanNearQueryBuilder = spanNearQuery(spanTermQuery(fields, cta.toString()), 0);
+                } else {
+                    spanNearQueryBuilder.addClause(spanTermQuery(fields, cta.toString()));
+                }
+            }
+
+            if (spanNearQueryBuilder == null || spanNearQueryBuilder.clauses().size() == 1) {
+                return termQuery(fields, content);
+            }
+            return spanNearQueryBuilder;
+        }
+    }
+
+
+    public static QueryBuilder existField(String field) {
+        return existField(field, Arrays.asList(""));
+    }
+
+    public static QueryBuilder existField(String field, List<String> ignoreStr) {
+        BoolQueryBuilder must = boolQuery()
+                .must(existsQuery(field));
+        if (ignoreStr != null && !ignoreStr.isEmpty()) {
+            BoolQueryBuilder boolQuery = boolQuery();
+            for (String s : ignoreStr) {
+                boolQuery.mustNot(termQuery(field, s));
+            }
+            must.must(boolQuery);
+        }
+        return must;
+    }
+
+    @SneakyThrows
+    public static void main(String[] args) {
+        String text = "2048";
+        try (Analyzer analyzer = new StandardAnalyzer()) {
+            TokenStream stream = analyzer.tokenStream("", text);
+            CharTermAttribute cta = stream.addAttribute(CharTermAttribute.class);
+            stream.reset();
+
+            while (stream.incrementToken()) {
+                System.out.println(cta.length());
+                System.out.println(cta.toString());
+            }
+        }
+    }
 }

+ 13 - 2
src/main/java/com/winhc/phoenix/example/util/company/search/CompanyIndexUtils.java

@@ -1,8 +1,11 @@
 package com.winhc.phoenix.example.util.company.search;
 
-import com.github.stuxuhai.jpinyin.ChineseHelper;
+import com.github.houbb.opencc4j.util.ZhConverterUtil;
 import org.apache.commons.lang3.StringUtils;
+import org.elasticsearch.script.Script;
+import org.elasticsearch.script.ScriptType;
 
+import java.util.Map;
 import java.util.regex.Pattern;
 
 /**
@@ -13,10 +16,18 @@ public class CompanyIndexUtils {
     private static final Pattern pattern = Pattern.compile("[^\\u4e00-\\u9fa50-9a-zA-Z]");
 
     public static String convertToSimplifiedChinese(String val) {
-        return StringUtils.isEmpty(val) ? null : ChineseHelper.convertToSimplifiedChinese(val);
+        return StringUtils.isEmpty(val) ? null : ZhConverterUtil.toSimple(val);
     }
 
     public static String cleanup(String val) {
         return StringUtils.isNotBlank(val) ? pattern.matcher(val).replaceAll("") : "";
     }
+
+    public static Script getScript(String scriptContent, Map<String, Object> map) {
+        return new Script(ScriptType.INLINE, "painless", scriptContent, map);
+    }
+
+    public static Script getScript(String scriptContent) {
+        return getScript(scriptContent, null);
+    }
 }

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

@@ -0,0 +1,37 @@
+package com.winhc.phoenix.example.util.company.search;
+
+import com.hankcs.hanlp.corpus.document.sentence.word.Word;
+import com.winhc.tool.nlp.WinhcTokenizer;
+import com.winhc.tool.nlp.utils.FamilyNameUtils;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author: XuJiakai
+ * 2021/12/10 14:27
+ */
+@Slf4j
+public class CompanySearchClassifyUtils {
+
+    private static WinhcTokenizer winhcTokenizer;
+
+    static {
+        try {
+            winhcTokenizer = WinhcTokenizer.getInstance();
+        } catch (IOException exception) {
+            throw new RuntimeException(exception);
+        }
+    }
+
+    public static boolean isPerson(String keyword) {
+        try {
+            List<Word> analyze = winhcTokenizer.analyze(keyword);
+            return analyze.size() == 1 && "nr".equals(analyze.get(0).getLabel()) && FamilyNameUtils.containsFamilyName(keyword);
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            return false;
+        }
+    }
+}

+ 207 - 22
src/main/java/com/winhc/phoenix/example/util/company/search/CompanySearchQueryUtils.java

@@ -1,5 +1,7 @@
 package com.winhc.phoenix.example.util.company.search;
 
+import com.winhc.tool.nlp.CompanyNameAnalyzer;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.elasticsearch.common.lucene.search.function.CombineFunction;
 import org.elasticsearch.index.query.*;
@@ -10,6 +12,7 @@ import org.elasticsearch.script.ScriptType;
 import org.elasticsearch.search.rescore.QueryRescoreMode;
 import org.elasticsearch.search.rescore.QueryRescorerBuilder;
 
+import java.io.IOException;
 import java.util.*;
 
 import static org.elasticsearch.index.query.QueryBuilders.*;
@@ -18,16 +21,31 @@ import static org.elasticsearch.index.query.QueryBuilders.*;
  * @author: XuJiakai
  * 2021/11/17 17:17
  */
+@Slf4j
 public class CompanySearchQueryUtils {
+    private static CompanyNameAnalyzer companyNameAnalyzer;
+
+    static {
+        try {
+            companyNameAnalyzer = new CompanyNameAnalyzer();
+        } catch (IOException exception) {
+            exception.printStackTrace();
+            throw new RuntimeException(exception);
+        }
+    }
+
+
     public static QueryBuilder getQueryBuilder(CompanyQueryVo companyQueryVo) {
 
         String content = companyQueryVo.getContent();
-        BoolQueryBuilder boolQuery = getBoolQuery(companyQueryVo);
+//        BoolQueryBuilder boolQuery = getPersonBoolQuery(companyQueryVo);
+//        BoolQueryBuilder boolQuery = getBoolQuery(companyQueryVo);
+        BoolQueryBuilder boolQuery = CompanySearchClassifyUtils.isPerson(content) ? getPersonBoolQuery(companyQueryVo) : getBoolQuery(companyQueryVo);
 
         //以下为过滤逻辑
         BoolQueryBuilder returnBoolQuery = boolQuery()
                 .filter(termQuery("deleted", "0"))
-                .filter(boolQuery().should(rangeQuery("company_score_weight").gt(0.3F))
+                .filter(boolQuery().should(rangeQuery("company_score_weight").gt(0.2F))
                         .should(termsQuery("company_type", "2"))
                 )
                 .must(boolQuery);
@@ -82,7 +100,7 @@ public class CompanySearchQueryUtils {
 
         Map<String, Object> map = new HashMap<String, Object>(2) {{
             put("query_content", content);
-            put("der", 0.85);
+            put("der", 0.9);//公司自有评分占比
         }};
         List<QueryRescorerBuilder> list = new ArrayList<>();
 
@@ -91,8 +109,17 @@ public class CompanySearchQueryUtils {
                 .windowSize(100)
                 .setScoreMode(QueryRescoreMode.Total));
 
+
         //乘上权重分
-        list.add(new QueryRescorerBuilder(functionScoreQuery(new ScriptScoreFunctionBuilder(new Script(ScriptType.STORED, null, "company-search-script_v2", map))))
+  /*      list.add(new QueryRescorerBuilder(functionScoreQuery(new ScriptScoreFunctionBuilder(
+                ElasticSearchScriptTest.getTestScript(map)
+        )))
+                .windowSize(100)
+                .setScoreMode(QueryRescoreMode.Multiply));*/
+
+
+        //乘上权重分
+        list.add(new QueryRescorerBuilder(functionScoreQuery(new ScriptScoreFunctionBuilder(new Script(ScriptType.STORED, null, "company-search-script_v3", map))))
                 .windowSize(100)
                 .setScoreMode(QueryRescoreMode.Multiply));
 
@@ -105,11 +132,137 @@ public class CompanySearchQueryUtils {
     }
 
 
+    /**
+     * 人员搜索
+     *
+     * @param companyQueryVo
+     * @return
+     */
+    private static BoolQueryBuilder getPersonBoolQuery(CompanyQueryVo companyQueryVo) {
+        log.debug("search keyword is person name: {} ", companyQueryVo.getContent());
+
+        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("cname.value", content).boost(0));
+        }
+
+        boolQuery.should(disMaxQuery()
+                        .add(disMaxQuery()
+                                        .add(termQuery("legal_entities.name.keyword", org_content).boost(10))
+                                        .add(termQuery("holder.name.keyword", content).boost(10F))
+                                        .add(termQuery("holder.name.keyword", org_content).boost(10F))
+                                        .add(termQuery("holder_history.name.keyword", content).boost(10F))
+                                        .add(termQuery("staff.name.keyword", content).boost(8F))
+                                        .add(termQuery("staff_history.name.keyword", content).boost(5.5F))
+//                        .tieBreaker(0.3F)
+                        )
+                        .add(disMaxQuery()
+                                        .add(matchQuery("legal_entities.name", org_content).boost(10).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(8).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(1))
+                        .add(termQuery("app_info.keyword", org_content).boost(2))
+                        .add(termQuery("company_tm.keyword", org_content).boost(1))
+                        .tieBreaker(0.4F))
+                .add(disMaxQuery()
+                        .add(matchPhraseQuery("icp", content).boost(1).slop(3))
+                        .add(matchPhraseQuery("app_info", content).boost(2).slop(3))
+                        .add(matchPhraseQuery("company_tm", org_content).boost(1).slop(1))
+                        .add(matchQuery("reg_location", content).boost(1).minimumShouldMatch("100%"))
+                        .tieBreaker(0.3F))
+                .tieBreaker(0.4F)
+        );
+
+
+        DisMaxQueryBuilder add = disMaxQuery().add(disMaxQuery()
+                .add(disMaxQuery()
+                        .add(matchPhraseQuery("cname.show.pinyin", content))
+                        .add(matchPhraseQuery("history_name.show.pinyin", content))
+                )
+                .add(disMaxQuery()
+                        .add(getSpanNearQuery("name_alias.standard", content).boost(1))
+                        .add(getSpanNearQuery("cname.show.standard", content).boost(1))
+                        .add(getSpanNearQuery("history_name.show.standard", content).boost(1))
+                )
+
+                .add(multiMatchQuery(content)
+                        .type(MultiMatchQueryBuilder.Type.CROSS_FIELDS)
+                        .minimumShouldMatch("100%")
+                        .tieBreaker(0.3F)
+
+                        .field("cname.show", 1)
+                        .field("name_alias", 1)
+                        .field("history_name.show", 1))
+                .add(multiMatchQuery(content)
+                        .operator(Operator.AND)
+                        .type(MultiMatchQueryBuilder.Type.CROSS_FIELDS)
+                        .tieBreaker(0.3F)
+                        .field("cname.show.standard", 1)
+                        .field("history_name.show.standard", 1))
+
+                .tieBreaker(0.4F));
+
+        String simplifiedChinese = CompanyIndexUtils.convertToSimplifiedChinese(org_content);
+        if (!StringUtils.equals(org_content, simplifiedChinese)) {
+            //添加繁体字简化查询
+            add.add(disMaxQuery()
+                    .add(disMaxQuery()
+                            .add(matchPhraseQuery("cname.simplified_chinese.pinyin", simplifiedChinese))
+                            .add(matchPhraseQuery("history_name.show.pinyin", simplifiedChinese))
+                    )
+                    .add(multiMatchQuery(simplifiedChinese)
+                            .type(MultiMatchQueryBuilder.Type.CROSS_FIELDS)
+                            .minimumShouldMatch("5<90%")
+                            .tieBreaker(0.3F)
+
+                            .field("cname.simplified_chinese", 1)
+                            .field("history_name.simplified_chinese", 1))
+                    .add(multiMatchQuery(simplifiedChinese)
+                            .operator(Operator.AND)
+                            .type(MultiMatchQueryBuilder.Type.CROSS_FIELDS)
+                            .tieBreaker(0.3F)
+                            .field("cname.simplified_chinese.standard", 1)
+                            .field("history_name.simplified_chinese.standard", 1))
+                    .tieBreaker(0.4F));
+        }
+
+        boolQuery.should(add);
+        return boolQuery;
+    }
+
+
+    /**
+     * 通用搜索
+     *
+     * @param companyQueryVo
+     * @return
+     */
     private static BoolQueryBuilder getBoolQuery(CompanyQueryVo companyQueryVo) {
+        log.debug("search keyword is not person name: {} ", companyQueryVo.getContent());
+
         BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
         String org_content = companyQueryVo.getContent();
         String content = CompanyQueryVo.cleanup(companyQueryVo.getContent());
 
+        String companyNameAlias = companyNameAnalyzer.nameAliasExtract(companyQueryVo.getContent());
+
         if (content.length() > 3) {
             boolQuery.should(disMaxQuery()
                     .add(termQuery("history_name.show.keyword", org_content))
@@ -127,25 +280,28 @@ public class CompanySearchQueryUtils {
                     .add(termQuery("phones.keyword", org_content).boost(1000))
                     .add(matchQuery("phones", org_content).boost(1000))
             );
-            boolQuery.should(termQuery("reg_location.keyword", org_content).boost(1000));
+            boolQuery.should(termQuery("reg_location.keyword", org_content).boost(100));
         }
 
         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)
+                        .add(disMaxQuery()
+//                        .add(termQuery("legal_entity_name.keyword", org_content).boost(10))
+                                .add(termQuery("legal_entities.name.keyword", org_content).boost(10))
+                                .add(termQuery("holder.name.keyword", content).boost(10F))
+                                .add(termQuery("holder.name.keyword", org_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(matchQuery("legal_entities.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()
@@ -166,23 +322,52 @@ public class CompanySearchQueryUtils {
         boolQuery.should(disMaxQuery()
                 .add(disMaxQuery()
                         .add(matchQuery("emails", org_content).boost(7).minimumShouldMatch("100%"))
-                        .add(matchQuery("icp_domain", org_content).boost(1000).minimumShouldMatch("100%"))
+                        .add(matchQuery("icp_domain", org_content).boost(1000).minimumShouldMatch("50%"))
 
                         .tieBreaker(0.3F))
                 .tieBreaker(0.4F)
         );
 
+     /*   Map<String, Object> map = new HashMap<String, Object>(1) {
+            {
+                put("name", content);
+            }
+        };
+
+        Script painless = new Script(ScriptType.INLINE, "painless", "String name_alias =  doc['name_alias.keyword'].value;if(name_alias==null)return false;return params.name.contains(name_alias);", map);
+
+        boolQuery.should(boolQuery()
+                .must(matchQuery("name_alias", content).operator(Operator.OR))
+                .must(scriptQuery(painless)));*/
+
+
         DisMaxQueryBuilder add = disMaxQuery().add(disMaxQuery()
                 .add(disMaxQuery()
                         .add(matchPhraseQuery("cname.show.pinyin", content))
                         .add(matchPhraseQuery("history_name.show.pinyin", content))
                 )
+                .add(disMaxQuery()
+                        .add(getSpanNearQuery("name_alias.standard", content).boost(20))
+                        .add(getSpanNearQuery("cname.show.standard", content).boost(10))
+                        .add(getSpanNearQuery("history_name.show.standard", content).boost(5))
+                )
+
                 .add(multiMatchQuery(content)
                         .type(MultiMatchQueryBuilder.Type.CROSS_FIELDS)
                         .minimumShouldMatch("5<90%")
                         .tieBreaker(0.3F)
 
                         .field("cname.show", 16)
+                        .field("name_alias", 20)
+                        .field("history_name.show", 12))
+
+                .add(multiMatchQuery(companyNameAlias)
+                        .type(MultiMatchQueryBuilder.Type.CROSS_FIELDS)
+                        .minimumShouldMatch("5<90%")
+                        .tieBreaker(0.3F)
+
+                        .field("cname.show", 16)
+                        .field("name_alias", 20)
                         .field("history_name.show", 12))
                 .add(multiMatchQuery(content)
                         .operator(Operator.AND)
@@ -194,7 +379,7 @@ public class CompanySearchQueryUtils {
                 .tieBreaker(0.4F));
 
         String simplifiedChinese = CompanyIndexUtils.convertToSimplifiedChinese(org_content);
-        if (StringUtils.isNotBlank(simplifiedChinese)) {
+        if (!StringUtils.equals(org_content, simplifiedChinese)) {
             //添加繁体字简化查询
             add.add(disMaxQuery()
                     .add(disMaxQuery()

+ 94 - 36
src/main/java/com/winhc/phoenix/example/util/company/search/CompanySearchTipsUtils.java

@@ -1,5 +1,6 @@
 package com.winhc.phoenix.example.util.company.search;
 
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.elasticsearch.index.query.*;
 import org.elasticsearch.index.query.functionscore.ScriptScoreFunctionBuilder;
@@ -19,10 +20,13 @@ import static org.elasticsearch.index.query.QueryBuilders.*;
  * @author: XuJiakai
  * 2021/12/31 11:01
  */
+@Slf4j
 public class CompanySearchTipsUtils {
     public static QueryBuilder tips(String content) {
 
-        BoolQueryBuilder boolQuery = getBoolQuery(content);
+//        BoolQueryBuilder boolQuery = getBoolQuery(content);
+        BoolQueryBuilder boolQuery = CompanySearchClassifyUtils.isPerson(content) ? getPersonBoolQuery(content) : getBoolQuery(content);
+
 
         //以下为过滤逻辑
         BoolQueryBuilder returnBoolQuery = boolQuery()
@@ -34,11 +38,11 @@ public class CompanySearchTipsUtils {
         return returnBoolQuery;
     }
 
-    private static BoolQueryBuilder getBoolQuery(String c) {
+    private static BoolQueryBuilder getBoolQuery(String org_content) {
+        log.debug("search tips keyword is not person name: {} ", org_content);
         BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
 
-        String org_content = c;
-        String content = CompanyIndexUtils.cleanup(c);
+        String content = CompanyIndexUtils.cleanup(org_content);
 
         if (content.length() > 3) {
             boolQuery.should(disMaxQuery()
@@ -60,19 +64,14 @@ public class CompanySearchTipsUtils {
 
         boolQuery.should(disMaxQuery()
                 .add(disMaxQuery()
-                        .add(termQuery("legal_entity_name.keyword", org_content).boost(10))
+//                        .add(termQuery("legal_entity_name.keyword", org_content).boost(10))
+                        .add(termQuery("legal_entities.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()
@@ -100,10 +99,6 @@ public class CompanySearchTipsUtils {
         );
 
         DisMaxQueryBuilder add = disMaxQuery().add(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%")
@@ -111,35 +106,18 @@ public class CompanySearchTipsUtils {
 
                         .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));
 
         String simplifiedChinese = CompanyIndexUtils.convertToSimplifiedChinese(org_content);
-        if (StringUtils.isNotBlank(simplifiedChinese)) {
+        if (!StringUtils.equals(org_content, simplifiedChinese)){
             //添加繁体字简化查询
             add.add(disMaxQuery()
-//                    .add(disMaxQuery()
-//                            .add(matchPhraseQuery("cname.simplified_chinese.pinyin", simplifiedChinese))
-//                            .add(matchPhraseQuery("history_name.show.pinyin", simplifiedChinese))
-//                    )
                     .add(multiMatchQuery(simplifiedChinese)
                             .type(MultiMatchQueryBuilder.Type.CROSS_FIELDS)
                             .minimumShouldMatch("5<90%")
                             .tieBreaker(0.3F)
-
                             .field("cname.simplified_chinese", 16)
                             .field("history_name.simplified_chinese", 12))
-//                    .add(multiMatchQuery(simplifiedChinese)
-//                            .operator(Operator.AND)
-//                            .type(MultiMatchQueryBuilder.Type.CROSS_FIELDS)
-//                            .tieBreaker(0.3F)
-//                            .field("cname.simplified_chinese.standard", 16)
-//                            .field("history_name.simplified_chinese.standard", 12))
                     .tieBreaker(0.4F));
         }
 
@@ -147,11 +125,91 @@ public class CompanySearchTipsUtils {
         return boolQuery;
     }
 
+    /**
+     * 人员搜索
+     *
+     * @param org_content
+     * @return
+     */
+    private static BoolQueryBuilder getPersonBoolQuery(String org_content) {
+        log.debug("search tips keyword is person name: {} ", org_content);
+        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
+
+        String content = CompanyIndexUtils.cleanup(org_content);
+
+        if (content.length() > 3) {
+            boolQuery.should(disMaxQuery()
+                    .add(termQuery("history_name.show.keyword", org_content))
+                    .add(termQuery("history_name.value", content))
+            );
+
+            boolQuery.should(termQuery("cname.value", content).boost(0));
+        }
+
+        boolQuery.should(disMaxQuery()
+                        .add(disMaxQuery()
+                                        .add(termQuery("legal_entities.name.keyword", org_content).boost(10))
+                                        .add(termQuery("holder.name.keyword", content).boost(10F))
+                                        .add(termQuery("holder.name.keyword", org_content).boost(10F))
+                                        .add(termQuery("holder_history.name.keyword", content).boost(10F))
+                                        .add(termQuery("staff.name.keyword", content).boost(8F))
+                                        .add(termQuery("staff_history.name.keyword", content).boost(5.5F))
+                        )
+                        .add(disMaxQuery()
+                                        .add(matchQuery("legal_entities.name", org_content).boost(10).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(8).slop(3))
+                                        .add(matchPhraseQuery("staff_history.name", content).boost(6).slop(3))
+                        )
+        );
+
+
+
+        DisMaxQueryBuilder add = disMaxQuery().add(disMaxQuery()
+                .add(multiMatchQuery(content)
+                        .operator(Operator.AND)
+                        .type(MultiMatchQueryBuilder.Type.CROSS_FIELDS)
+                        .tieBreaker(0.3F)
+                        .field("cname.show.standard", 1)
+                        .field("history_name.show.standard", 1))
+
+                .tieBreaker(0.4F));
+
+        String simplifiedChinese = CompanyIndexUtils.convertToSimplifiedChinese(org_content);
+        if (!StringUtils.equals(org_content, simplifiedChinese)) {
+            //添加繁体字简化查询
+            add.add(disMaxQuery()
+                    .add(disMaxQuery()
+                            .add(matchPhraseQuery("cname.simplified_chinese.pinyin", simplifiedChinese))
+                            .add(matchPhraseQuery("history_name.show.pinyin", simplifiedChinese))
+                    )
+                    .add(multiMatchQuery(simplifiedChinese)
+                            .type(MultiMatchQueryBuilder.Type.CROSS_FIELDS)
+                            .minimumShouldMatch("5<90%")
+                            .tieBreaker(0.3F)
+
+                            .field("cname.simplified_chinese", 1)
+                            .field("history_name.simplified_chinese", 1))
+                    .add(multiMatchQuery(simplifiedChinese)
+                            .operator(Operator.AND)
+                            .type(MultiMatchQueryBuilder.Type.CROSS_FIELDS)
+                            .tieBreaker(0.3F)
+                            .field("cname.simplified_chinese.standard", 1)
+                            .field("history_name.simplified_chinese.standard", 1))
+                    .tieBreaker(0.4F));
+        }
+
+        boolQuery.should(add);
+        return boolQuery;
+    }
+
+
     public static List<QueryRescorerBuilder> getReScoreBuilder(String content) {
         String c = CompanyIndexUtils.convertToSimplifiedChinese(CompanyIndexUtils.cleanup(content));
         Map<String, Object> map = new HashMap<String, Object>(2) {{
             put("query_content", c);
-            put("der", 0.85);
+            put("der", 0.9);
         }};
         List<QueryRescorerBuilder> list = new ArrayList<>();
 
@@ -161,7 +219,7 @@ public class CompanySearchTipsUtils {
                 .setScoreMode(QueryRescoreMode.Total));
 
         //乘上权重分
-        list.add(new QueryRescorerBuilder(functionScoreQuery(new ScriptScoreFunctionBuilder(new Script(ScriptType.STORED, null, "company-search-script_v2", map))))
+        list.add(new QueryRescorerBuilder(functionScoreQuery(new ScriptScoreFunctionBuilder(new Script(ScriptType.STORED, null, "company-search-script_v3", map))))
                 .windowSize(50)
                 .setScoreMode(QueryRescoreMode.Multiply));
         return list;

+ 74 - 0
src/main/java/com/winhc/phoenix/example/util/company/search/ElasticSearchScriptTest.java

@@ -0,0 +1,74 @@
+package com.winhc.phoenix.example.util.company.search;
+
+import org.elasticsearch.script.Script;
+
+import java.util.Map;
+
+/**
+ * @author: XuJiakai
+ * 2021/8/9 14:50
+ */
+public class ElasticSearchScriptTest {
+
+
+    public static Script getTestScript(Map<String, Object> map) {
+        return CompanyIndexUtils.getScript("double w = doc['company_score_weight'].value;" +
+                "if(doc['company_type'].value!=null&&doc['company_type'].value.equals('4'))w = w+4;" +
+                "if(params.query_content.contains('律'))w = w+1; " +
+                "if(doc['app_info.keyword'].values!=null){int size = doc['app_info.keyword'].values.size();" +
+                "if(size<3)w = w+2;" +
+                "else if(size<8) w=w+3;" +
+                "else if(size<15) w=w+4;" +
+                "else if(size<100) w=w+8;" +
+                "else w=w+10;" +
+                "}" +
+                "if(doc['company_tm.keyword'].values!=null){int size = doc['company_tm.keyword'].values.size();" +
+                "if(size<80)w = w+0;" +
+                "else if(size<100) w=w+3;" +
+                "else if(size<200) w=w+4;" +
+                "else if(size<1000) w=w+8;" +
+                "else w=w+10;" +
+                "}" +
+                "if(doc['tags.tag_code'].values!=null){int size = doc['tags.tag_code'].values.size();" +
+                "if(size<=2)w = w+1;" +
+                "else w=w+2;" +
+                "if(doc['tags.tag_code'].values.contains('b_001')) w=w+4;" +
+                "}" +
+                "double r = 0d;" +
+                "if(doc['company_rank'].value!=null)r = doc['company_rank'].value;" +
+                "return w*params.der+r*(1-params.der);", map);
+    }
+
+
+    public static void main(String[] args) {
+        String script = "double w = doc['company_score_weight'].value;" +
+                "if(doc['company_type'].value!=null&&doc['company_type'].value.equals('4'))w = w+4;" +
+                "if(params.query_content.contains('律'))w = w+1; " +
+                "if(doc['app_info.keyword'].values!=null){int size = doc['app_info.keyword'].values.size();" +
+                "if(size<3)w = w+2;" +
+                "else if(size<8) w=w+3;" +
+                "else if(size<15) w=w+4;" +
+                "else if(size<100) w=w+8;" +
+                "else w=w+10;" +
+                "}" +
+                "if(doc['company_tm.keyword'].values!=null){int size = doc['company_tm.keyword'].values.size();" +
+                "if(size<80)w = w+0;" +
+                "else if(size<100) w=w+3;" +
+                "else if(size<200) w=w+4;" +
+                "else if(size<1000) w=w+8;" +
+                "else w=w+10;" +
+                "}" +
+                "if(doc['tags.tag_code'].values!=null){int size = doc['tags.tag_code'].values.size();" +
+                "if(size<=2)w = w+1;" +
+                "else w=w+2;" +
+                "if(doc['tags.tag_code'].values.contains('b_001')) w=w+4;" +
+                "}" +
+                "double r = 0d;" +
+                "if(doc['company_rank'].value!=null)r = doc['company_rank'].value;" +
+                "return w*params.der+r*(1-params.der);";
+
+        System.out.println(script);
+    }
+
+
+}

+ 9 - 0
src/main/java/com/winhc/phoenix/example/vo/judgment/CourtLevels.java

@@ -0,0 +1,9 @@
+package com.winhc.phoenix.example.vo.judgment;
+
+/**
+ * @author: XuJiakai
+ * 2022/7/29 11:47
+ */
+public enum CourtLevels {
+
+}

+ 107 - 0
src/main/java/com/winhc/phoenix/example/vo/judgment/JudgmentDocumentsSearchContent.java

@@ -0,0 +1,107 @@
+package com.winhc.phoenix.example.vo.judgment;
+
+
+import cn.hutool.crypto.SecureUtil;
+import lombok.Getter;
+import lombok.ToString;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author: XuJiakai
+ * 2022/7/29 11:43
+ */
+@Getter
+@ToString
+public class JudgmentDocumentsSearchContent {
+    private int from = 0;
+    private int size = 10;
+
+    private boolean authorityCase = false;
+    private boolean notSort = false;
+
+    private String ip;
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    private Map<String, JudgmentDocumentsSearchType> content;
+
+    /**
+     * 法院层级
+     */
+    private List<CourtLevels> courtLevels;
+
+    /**
+     * 筛选:专门法院、审理法院
+     */
+    private List<String> courtCode;
+
+    /**
+     * 筛选:地域
+     */
+    private List<String> areaCode;
+
+    /**
+     * 案由,|分割
+     */
+    private List<String> caseCause;
+
+    /**
+     * 审判程序
+     */
+    private List<String> judicialProcedure;
+
+    /**
+     * 文书性质:判决书、裁定书
+     */
+    private List<String> documentType;
+
+    /**
+     * 审判年份。如果是范围则用  [202101,202201] ,闭区间
+     */
+    private List<String> judgmentYear;
+
+    /**
+     * 文书来源类型:指导性案例、公报案例、普通案例...
+     */
+    private List<String> documentSourceType;
+
+    /**
+     * 审判结果
+     */
+    private List<String> judgmentResult;
+
+    /**
+     * 文章字数。[,100]、[100,200]、[10000,]
+     */
+    private List<String> wordCount;
+
+
+    /**
+     * 量刑情节。自首、坦白、立功...
+     */
+    private List<String> sentencingCircumstances;
+
+    /**
+     * 争议焦点
+     */
+    private List<String> disputeFocus;
+
+
+    /**
+     * 案情
+     */
+    private List<String> caseDetails;
+
+
+    public String getPreference() {
+        return SecureUtil.md5(String.join("", content.keySet()));
+    }
+
+
+    private JudgmentDocumentsSortType sort;
+
+}

+ 71 - 0
src/main/java/com/winhc/phoenix/example/vo/judgment/JudgmentDocumentsSearchType.java

@@ -0,0 +1,71 @@
+package com.winhc.phoenix.example.vo.judgment;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author: XuJiakai
+ * 2022/7/29 11:44
+ */
+@SuppressWarnings("all")
+public enum JudgmentDocumentsSearchType {
+    ALL,
+    /**
+     * 案号
+     */
+    CASE_NO(Arrays.asList("case_no", "case_no.keyword")),
+    /**
+     * 书记员
+     */
+    COURT_CLERK(Arrays.asList("clerk")),
+    /**
+     * 法院名称
+     */
+    COURT_NAME(Arrays.asList("court_name")),
+    /**
+     * 本院认为(法院认为)
+     */
+    COURT_VIEW(Arrays.asList("court_view")),
+    /**
+     * 审理经过(包含原告诉称、被告辩称、审理查明)
+     */
+    FACT(Arrays.asList("fact")),
+    /**
+     * 法官
+     */
+    JUDGE(Arrays.asList("judge")),
+    /**
+     * 裁判结果
+     */
+    JUDGE_RESULT(Arrays.asList("judge_result")),
+    /**
+     * 当事人
+     */
+    PARTY_INFO(Arrays.asList("party_info")),
+    /**
+     * 标题
+     */
+    TITLE(Arrays.asList("title")),
+
+
+    ;
+
+    public static final Set<String> KEYWORD_FIELDS = new HashSet<String>(){{
+        add("case_no.keyword");
+    }};
+
+    JudgmentDocumentsSearchType(List<String> fields) {
+        this.fields = fields;
+    }
+
+    JudgmentDocumentsSearchType() {
+    }
+
+    private List<String> fields;
+
+    public List<String> getFields() {
+        return fields;
+    }
+}

+ 9 - 0
src/main/java/com/winhc/phoenix/example/vo/judgment/JudgmentDocumentsSortType.java

@@ -0,0 +1,9 @@
+package com.winhc.phoenix.example.vo.judgment;
+
+/**
+ * @author: XuJiakai
+ * 2022/7/29 15:22
+ */
+public enum JudgmentDocumentsSortType {
+    AS
+}

+ 105 - 0
src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientConfigurations.java

@@ -0,0 +1,105 @@
+package org.springframework.boot.autoconfigure.elasticsearch;
+
+import org.apache.http.HttpHost;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
+import org.elasticsearch.client.RestClient;
+import org.elasticsearch.client.RestClientBuilder;
+import org.elasticsearch.client.RestHighLevelClient;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.context.properties.PropertyMapper;
+
+import java.time.Duration;
+
+/**
+ * @author: XuJiakai
+ * 2021/8/5 14:22
+ */
+public class ElasticsearchRestClientConfigurations {
+    static class RestClientBuilderConfiguration {
+
+        RestClientBuilderCustomizer defaultRestClientBuilderCustomizer(ElasticsearchRestClientProperties properties) {
+            return new DefaultRestClientBuilderCustomizer(properties);
+        }
+
+        RestClientBuilder elasticsearchRestClientBuilder(ElasticsearchRestClientProperties properties,
+                                                         ObjectProvider<RestClientBuilderCustomizer> builderCustomizers) {
+            HttpHost[] hosts = properties.getUris().stream().map(HttpHost::create).toArray(HttpHost[]::new);
+            RestClientBuilder builder = RestClient.builder(hosts);
+            builder.setHttpClientConfigCallback((httpClientBuilder) -> {
+                builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(httpClientBuilder));
+                return httpClientBuilder;
+            });
+            builder.setRequestConfigCallback((requestConfigBuilder) -> {
+                builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(requestConfigBuilder));
+                return requestConfigBuilder;
+            });
+            builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
+            return builder;
+        }
+
+    }
+
+    static class RestHighLevelClientConfiguration {
+
+        RestHighLevelClient elasticsearchRestHighLevelClient(RestClientBuilder restClientBuilder) {
+            return new RestHighLevelClient(restClientBuilder.build());
+        }
+
+        RestClient elasticsearchRestClient(RestClientBuilder builder,
+                                           ObjectProvider<RestHighLevelClient> restHighLevelClient) {
+            RestHighLevelClient client = restHighLevelClient.getIfUnique();
+            return builder.build();
+        }
+
+    }
+
+    static class RestClientFallbackConfiguration {
+
+        RestClient elasticsearchRestClient(RestClientBuilder builder) {
+            return builder.build();
+        }
+
+    }
+
+    static class DefaultRestClientBuilderCustomizer implements RestClientBuilderCustomizer {
+
+        private static final PropertyMapper map = PropertyMapper.get();
+
+        private final ElasticsearchRestClientProperties properties;
+
+        DefaultRestClientBuilderCustomizer(ElasticsearchRestClientProperties properties) {
+            this.properties = properties;
+        }
+
+        @Override
+        public void customize(RestClientBuilder builder) {
+        }
+
+        @Override
+        public void customize(HttpAsyncClientBuilder builder) {
+            map.from(this.properties::getUsername).whenHasText().to((username) -> {
+                CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
+                Credentials credentials = new UsernamePasswordCredentials(this.properties.getUsername(),
+                        this.properties.getPassword());
+                credentialsProvider.setCredentials(AuthScope.ANY, credentials);
+                builder.setDefaultCredentialsProvider(credentialsProvider);
+            });
+        }
+
+        @Override
+        public void customize(RequestConfig.Builder builder) {
+            map.from(this.properties::getConnectionTimeout).whenNonNull().asInt(Duration::toMillis)
+                    .to(builder::setConnectTimeout);
+            map.from(this.properties::getReadTimeout).whenNonNull().asInt(Duration::toMillis)
+                    .to(builder::setSocketTimeout);
+        }
+
+    }
+
+}

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

@@ -1,3 +1,9 @@
+logging:
+  level:
+    root: WARN
+    com.winhc: DEBUG
+
+
 spring:
   datasource:
     phoenix:
@@ -7,6 +13,7 @@ spring:
   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

+ 5 - 1
src/main/resources/application-prod.yml

@@ -1,5 +1,9 @@
-spring:
+logging:
+  level:
+    root: WARN
+    com.winhc: DEBUG
 
+spring:
   datasource:
     phoenix:
       server:

Разница между файлами не показана из-за своего большого размера
+ 8 - 0
src/main/resources/static/js/base64.min.js


+ 43 - 3
src/main/resources/static/search-company.html

@@ -72,11 +72,15 @@
                 console.log('查询耗时:', res.took)
                 var rows = res.hits.hits.map(function (value, index, array) {
                     value._source.company_id = value._id
+                    let legal_entity_name = value._source.legal_entities?value._source.legal_entities.map(function(items,index){
+                        return items.name;
+                    }).join(","):value._source.legal_entity_name;
                     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_rank_sec": value._source.company_rank_sec,
+                        "legal_entity_name": legal_entity_name,
                         "company_score_weight": value._source.company_score_weight,
                         "score": value._score,
                         "record": value._source,
@@ -114,10 +118,19 @@
                     formatter: highlight
                 },
                 {
+                    title: '标签',
+                    field: 'company_id',
+                    formatter: tags_func
+                },
+                {
                     title: 'company_rank',
                     field: 'company_rank',
                 },
                 {
+                    title: 'company_rank_sec',
+                    field: 'company_rank_sec',
+                },
+                {
                     title: 'company_score_weight',
                     field: 'company_score_weight',
                 },
@@ -125,8 +138,6 @@
                     title: '排序分',
                     field: 'score',
                 }
-
-
                 , {
                     title: '操作',
                     field: 'record',
@@ -149,6 +160,7 @@
         let m = {
             "cname.value": "名称",
             "cname.show": "名称",
+            "name_alias": "字号",
             "cname.show.keyword": "名称",
             "cname.value.pinyin": "名称拼音",
             "cname.show.pinyin": "名称拼音",
@@ -197,6 +209,34 @@
         return htm;
     }
 
+
+    function tags_func(value, row, index) {
+        let company_id = row.company_id;
+        let htm =
+            '<div id="'+company_id+'_tag" class="row my-label">'
+        $.get("/hbase/scan/ng_rt_company_tags/"+company_id+"_?size=100",function(data,status){
+            if(data.success){
+                if(data.data){
+                    for (let i = data.data.length - 1; i >= 0; i--) {
+                        console.log(data.data[i].TAG_NAME);
+                        console.log(data.data[i].DELETED);
+                        if(data.data[i].DELETED !== '0'){
+                            continue;
+                        }
+                        let ht =  '<span class="my-badge">' + data.data[i].TAG_NAME + '</span>';
+                        $("#"+company_id+"_tag").append(ht)
+
+                    }
+                }
+            }else{
+                alert("请求失败:"+data.msg)
+            }
+        });
+
+        htm += '</div>'
+        return htm;
+    }
+
     // 定义删除、更新按钮
     function option(value, row, index) {
         var name = value.cname.show

+ 422 - 0
src/main/resources/static/search-wenshu.html

@@ -0,0 +1,422 @@
+<!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>
+    <link href="https://cdn.bootcss.com/bootstrap-switch/4.0.0-alpha.1/css/bootstrap-switch.min.css" rel="stylesheet">
+    <script src="https://cdn.bootcss.com/bootstrap-switch/4.0.0-alpha.1/js/bootstrap-switch.min.js"></script>
+</head>
+<body>
+
+<div id="search" style="margin-top:80px;margin-left: 80px;margin-right: 80px">
+    <div class="container">
+        <div class="row .col-md-3">
+            <div class="input-group">
+                  <span class="input-group-btn">
+                        <input type="checkbox" name="my-checkbox" checked>
+                    </span>
+                <span class="input-group-btn">
+                        <input type="checkbox" name="sort-checkbox" checked>
+                    </span>
+                <div class="input-group-btn">
+                    <button id="search-scope" enum_value="ALL" type="button" class="btn btn-default dropdown-toggle"
+                            data-toggle="dropdown">
+                        全文内容
+                        <span class="caret"></span>
+                    </button>
+                    <ul class="dropdown-menu">
+                        <li><a name="click_menu" enum_value="ALL">全文内容</a></li>
+                        <li><a name="click_menu" enum_value="TITLE">标题</a></li>
+                        <li><a name="click_menu" enum_value="COURT_VIEW">本院认为</a></li>
+                        <li><a name="click_menu" enum_value="JUDGE_RESULT">裁判结果</a></li>
+                        <li><a name="click_menu" enum_value="FACT">审理经过</a></li>
+                        <li><a name="click_menu" enum_value="PARTY_INFO">当事人</a></li>
+                    </ul>
+                </div>
+                <input id="search-content" type="text" class="form-control">
+                <span class="input-group-btn">
+                        <button class="btn btn-default" type="button" onclick="javascript:search(true)">新搜索</button>
+                    </span>
+                <span class="input-group-btn">
+                        <button class="btn btn-default" type="button" onclick="javascript:search(false)">在结果中搜索</button>
+                    </span>
+            </div>
+        </div>
+    </div>
+
+    <div class="row">
+        <div id="search-list" class="row">
+        </div>
+    </div>
+    <br>
+
+    <div class="row">
+        <div id="model">
+        </div>
+    </div>
+
+    <div class="row">
+        <table id="search-result" class="table table-hover"></table>
+    </div>
+
+
+    <script>
+        let authorityCase = false;
+        let notSort = false;
+        $("[name='my-checkbox']").bootstrapSwitch({
+            onText: "普通案例",      // 设置ON文本
+            offText: "权威案例",    // 设置OFF文本
+            onColor: "success",// 设置ON文本颜色(info/success/warning/danger/primary)
+            offColor: "info",  // 设置OFF文本颜色 (info/success/warning/danger/primary)
+            size: "large",    // 设置控件大小,从小到大  (mini/small/normal/large)
+            // 当开关状态改变时触发
+            onSwitchChange: function (event, state) {
+                if (state == true) {
+                    authorityCase = false;
+                } else {
+                    authorityCase = true;
+                }
+            }
+        });
+        $("[name='sort-checkbox']").bootstrapSwitch({
+            onText: "排序",      // 设置ON文本
+            offText: "不排序",    // 设置OFF文本
+            onColor: "success",// 设置ON文本颜色(info/success/warning/danger/primary)
+            offColor: "warning",  // 设置OFF文本颜色 (info/success/warning/danger/primary)
+            size: "large",    // 设置控件大小,从小到大  (mini/small/normal/large)
+            // 当开关状态改变时触发
+            onSwitchChange: function (event, state) {
+                if (state == true) {
+                    notSort = false;
+                } else {
+                    notSort = true;
+                }
+            }
+        });
+        let flag = false;
+
+        function init() {
+            $('#search-result').bootstrapTable({
+                method: 'post',
+                dataType: "json",
+                // url: "http://xjk:8288/judgment/query", // 请求路径
+                url: "/judgment/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) { // 上传服务器的参数
+                    let map = {}
+                    let search_list = $('#search-list').children();
+                    for (let i = 0; i < search_list.length; i++) {
+                        map[search_list[i].getAttribute('search_content').trim()] = search_list[i].getAttribute('search_enum').trim();
+                    }
+                    var temp = {
+                        content: map,
+                        authorityCase: authorityCase,
+                        notSort: notSort,
+                        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)
+                    console.log('查询耗时:', res.took)
+                    var rows = res.hits.hits.map(function (value, index, array) {
+                        return {
+                            "doc_id": value._id,
+                            "title": value._source.title,
+                            "case_no": value._source.case_no,
+                            "court_name": value._source.court_name,
+                            "judge_date": value._source.judge_date ? value._source.judge_date.split(' ')[0] : value._source.judge_date,
+                            "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: 'doc_id',
+                        visible: false
+                    },
+                    {
+                        title: '案件doc_id',
+                        field: 'doc_id',
+
+                    },
+                    {
+                        title: 'title',
+                        field: 'title',
+                    },
+                    {
+                        title: '案号',
+                        field: 'case_no',
+                    },
+                    {
+                        title: '来源',
+                        field: 'highlight',
+                        formatter: highlight,
+                        cellStyle: formatTableUnit,
+                        // formatter :paramsMatter,
+                    },
+                    {
+                        title: '法院',
+                        field: 'court_name',
+                    },
+                    {
+                        title: '审理日期',
+                        field: 'judge_date',
+                    },
+                    // {
+                    //     title: '排序分',
+                    //     field: 'score',
+                    // } ,
+                    {
+                        title: '操作',
+                        field: 'record',
+                        formatter: option
+                    }
+
+                ]
+            })
+            flag = true
+        }
+
+
+        $("#search").keypress(function (event) {
+            if (event.which === 13) {
+                search(true);
+            }
+        })
+
+        $("[name='click_menu']").click(function(){
+            $('#search-scope').text($(this).text());
+            $('#search-scope').attr('enum_value', $(this).attr('enum_value'));
+        });
+
+
+        function highlight(value, row, index) {
+            let m = {
+                "addenda": "附录文本",
+                "case_no": "案号",
+                "case_no.keyword": "案号",
+                "clerk": "书记员",
+                "court_name.keyword": "法院",
+                "court_name": "法院",
+                "court_view": "法院观点",
+                "fact": "审理经过",
+                "judge": "承办法官",
+                "judge_result": "裁判结果",
+                "party_info": "当事人",
+                "title": "标题",
+            }
+            if (!value) {
+                return '';
+            }
+            let htm =
+                '<div class="row my-label" style="overflow:scroll;overflow-y:hidden">'
+
+            for (let mKey in m) {
+                if (value[mKey]) {
+                    let s = value[mKey].map(function (v, i, a) {
+                        v = v.replaceAll(")", ")").replaceAll("(", "(");
+                        if (v.indexOf("</font>)<font class='my-bold'>") > 0 && v.indexOf("</font>(<font class='my-bold'>") > 0) {
+                            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) {
+            console.log(row.doc_id)
+            var p = 'https://www.winhc.cn/searchCase/' + Base64.encodeURI(row.doc_id);
+            return '<button class="btn btn-primary btn-lg" onclick="javascript:window.open(\'' + p + '\')">详情</button>';
+        }
+
+
+        function search(clear = false) {
+
+            let search_scope = $('#search-scope').text();
+            let search_enum = $('#search-scope').attr('enum_value');
+            let search_content = $('#search-content').val();
+            if (search_content !== '') {
+                if (clear) {
+                    $('#search-list').empty();
+                }
+                $('#search-list').html($('#search-list').html() + ' <span class="my-badge" search_enum="' + search_enum + '" search_content="' + search_content + '">' + search_scope + ': ' + search_content + '</span>')
+            }
+
+            if (!flag) {
+                console.info('init...')
+                init()
+            } else {
+                console.info('search...')
+                $('#search-result').bootstrapTable('refresh', {pageSize: 10, pageNumber: 1});
+            }
+            $('#search-scope').text('全部内容');
+            $('#search-scope').attr('enum_value', 'ALL');
+            $('#search-content').val("");
+        }
+
+        //表格超出宽度鼠标悬停显示td内容
+        function paramsMatter(value, row, index) {
+            let m = {
+                "addenda": "附录文本",
+                "case_no": "案号",
+                "case_no.keyword": "案号",
+                "clerk": "书记员",
+                "court_name.keyword": "法院",
+                "court_name": "法院",
+                "court_view": "法院观点",
+                "fact": "审理经过",
+                "judge": "承办法官",
+                "judge_result": "裁判结果",
+                "party_info": "当事人",
+                "title": "标题",
+            }
+            if (!value) {
+                return '';
+            }
+            let htm =
+                '<div class="row my-label" style="overflow:scroll;">'
+
+            for (let mKey in m) {
+                if (value[mKey]) {
+                    let s = value[mKey].map(function (v, i, a) {
+                        v = v.replaceAll(")", ")").replaceAll("(", "(");
+                        if (v.indexOf("</font>)<font class='my-bold'>") > 0 && v.indexOf("</font>(<font class='my-bold'>") > 0) {
+                            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>'
+
+
+            var span = document.createElement("span");
+            span.setAttribute("title", htm);
+            span.innerHTML = htm;
+            return span.outerHTML;
+        }
+
+        //td宽度以及内容超过宽度隐藏
+        function formatTableUnit(value, row, index) {
+            return {
+                css: {
+                    "white-space": "nowrap",
+                    "text-overflow": "ellipsis",
+                    "overflow": "hidden",
+                    "max-width": "240px"
+                }
+            }
+        }
+
+
+    </script>
+
+    <style>
+
+        #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>