瀏覽代碼

智能搜索,阶段1

周壕 9 月之前
父節點
當前提交
a6d6a45cb9

+ 38 - 0
src/main/java/com/bowintek/practice/controller/EsQueryController.java

@@ -0,0 +1,38 @@
+package com.bowintek.practice.controller;
+
+import com.bowintek.practice.AppConfig;
+import com.bowintek.practice.filter.exception.BaseResponse;
+import com.bowintek.practice.filter.exception.RespGenerstor;
+import com.bowintek.practice.mapper.SrSaerchtempMapper;
+import com.bowintek.practice.mapper.SrTempDataMapper;
+import com.bowintek.practice.model.SrSaerchtemp;
+import com.bowintek.practice.model.SrTempData;
+import com.bowintek.practice.services.service.*;
+import com.bowintek.practice.vo.Analyze.ComparisonResult;
+import com.bowintek.practice.vo.SaerchtempVo;
+import com.bowintek.practice.vo.system.RoleModel;
+import com.bowintek.practice.vo.temp.GenSqlStringResult;
+import com.bowintek.practice.vo.temp.TempObjectModel;
+import com.github.pagehelper.PageInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/api/esquery")
+public class EsQueryController {
+    @Autowired
+    private EsQueryService esQueryService;
+
+    @GetMapping("/getQuery")
+    public BaseResponse getQuery(String text, int page, int limit) {
+        Map<String, Object> results = esQueryService.query(text, page, limit);
+        return RespGenerstor.success(results);
+    }
+}

+ 2 - 0
src/main/java/com/bowintek/practice/controller/TempController.java

@@ -57,6 +57,8 @@ public class TempController {
     @Autowired
     private AnalyzeService analyzeService;
     @Autowired
+    private EsQueryService esQueryService;
+    @Autowired
     private QueryLogService queryLogService;
     @Autowired
     private OrganizationService organizationService;

+ 172 - 0
src/main/java/com/bowintek/practice/services/impl/EsQueryServiceImpl.java

@@ -0,0 +1,172 @@
+package com.bowintek.practice.services.impl;
+
+import co.elastic.clients.elasticsearch.ElasticsearchClient;
+import co.elastic.clients.elasticsearch._types.mapping.Property;
+import co.elastic.clients.elasticsearch._types.mapping.TextProperty;
+import co.elastic.clients.elasticsearch._types.query_dsl.*;
+import co.elastic.clients.elasticsearch.cat.IndicesResponse;
+import co.elastic.clients.elasticsearch.core.SearchRequest;
+import co.elastic.clients.elasticsearch.core.SearchResponse;
+import co.elastic.clients.elasticsearch.core.search.Hit;
+import co.elastic.clients.elasticsearch.indices.PutMappingRequest;
+import co.elastic.clients.elasticsearch.indices.PutMappingResponse;
+import co.elastic.clients.json.JsonData;
+import com.bowintek.practice.services.service.AnalyzeService;
+import com.bowintek.practice.services.service.EsQueryService;
+import com.bowintek.practice.util.StringUtils;
+import com.bowintek.practice.vo.Analyze.ComparisonResult;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.naming.directory.SearchResult;
+import java.io.IOException;
+import java.util.*;
+
+@Component
+public class EsQueryServiceImpl implements EsQueryService {
+    @Autowired
+    private ElasticsearchClient esClient;
+    @Autowired
+    private AnalyzeService analyzeService;
+
+    @Override
+    public Map<String, Object> query(String text, int page, int limit) {
+        //[1]需要返回的结果map
+        Map<String, Object> result = new HashMap<>();
+        result.put("total", 0);
+        //[2]分析查询字符串,有的字符串需要变成条件查询
+        List<ComparisonResult> cmpList = analyzeService.analyzeJavas(text);
+        //[3]有查询条件分析内容,组装查询条件
+        List<Query> queryList = new ArrayList<>();
+        for(int i=0;i<cmpList.size();i++){
+            ComparisonResult cmp = cmpList.get(i);
+            if(cmp.getSearchType().equals("comparison")){
+                //对比搜索
+
+            }
+            else{
+                //query 文字搜索
+            }
+        }
+
+        return result;
+    }
+
+    public Map<String, Object> query1(String text, int page, int limit) {
+        Map<String, Object> result = new HashMap<>();
+        result.put("total", 0);
+
+        try {
+            IndicesResponse indicesResponse = esClient.cat().indices();
+            indicesResponse.valueBody().forEach(i -> {
+                System.out.println("get all index, health: " + i.health() + ", status: " + i.status() + ", index: " + i.index());
+            });
+
+            //建立查询参数分析
+            SearchRequest.Builder searchRequest = new SearchRequest.Builder();
+            //要查询的索引列表
+            String[] indexs = new String[]{"dws_basic_info_history", "dws_dm_test_history", "fact_dwr_well_basic_information"};
+            searchRequest.index(Arrays.asList(indexs));
+            //数据分页显示
+            searchRequest.size(limit);
+            searchRequest.from(page * limit);
+
+            //生成查询参数
+            if(!StringUtils.IsNullEmpty(text)) {
+                //非嵌套字段查询
+                String[] fields = new String[]{"well_common_name","testing_name"};
+                Query query1 = MultiMatchQuery.of(q -> q.fields(Arrays.asList(fields)).query(text).operator(Operator.Or))._toQuery();
+                //嵌套字段查询
+                String[] nestedFields = new String[]{"historys.testing_name"};
+                Query nestedQuery = MultiMatchQuery.of(q -> q.fields(Arrays.asList(nestedFields)).query(text).operator(Operator.Or))._toQuery();
+                Query query3 = NestedQuery.of(q-> q.path("historys").query(nestedQuery).ignoreUnmapped(true))._toQuery();
+                //对比类型查询
+                Query query2 = RangeQuery.of(q->q.field("authorized_md").gte(JsonData.of(500)))._toQuery();
+
+                Query[] arys = new Query[]{query1, query2, query3};
+                searchRequest.query(q->q.bool(b->b.should(Arrays.asList(arys))));
+                //高亮设置
+                searchRequest.highlight(h->h.fields("historys.testing_name", f->f.matchedFields("historys.testing_name")));
+            }
+
+            //Es发起查询
+            SearchRequest request = searchRequest.build();
+            SearchResponse response = esClient.search(request, ObjectNode.class);
+
+            //转换结果,可以对不同的index做出参数输出
+            List<Map<String, Object>> rows = searchResponse2List(response);
+            result.put("rows", rows);
+            result.put("total", response.hits().total().value());
+            System.out.println(response.hits().total()+" "+ request.toString());
+        }
+        catch (Exception ex){
+            ex.printStackTrace();
+        }
+        return result;
+    }
+
+    public void updateMappingTest() throws IOException {
+        Map<String, Property> maps = new HashMap<>();
+        maps.put("well_common_name", Property.of(p->p.text(TextProperty.of(t->t.index(true).analyzer("ik_max_word")))));
+        updateMappings("fact_dwr_well_basic_information", maps);
+    }
+
+    public void updateMappings(String index, Map<String, Property> maps) throws IOException {
+        PutMappingRequest putMappingRequest = PutMappingRequest.of(m -> m.index(index).properties(maps));
+        PutMappingResponse putMappingResponse = esClient.indices().putMapping(putMappingRequest);
+        boolean acknowledged = putMappingResponse.acknowledged();
+        System.out.println("update mappings ack: " + acknowledged);
+    }
+
+    public List<Map<String, Object>> searchResponse2List(SearchResponse<ObjectNode> searchResponse) {
+
+        if (searchResponse == null) {return new ArrayList<>(0);}
+        if (searchResponse.hits() == null) {return new ArrayList<>(0);}
+        //if (CommonUtils.isCollectionEmpty(searchResponse.hits().hits())) {return new ArrayList<>(0);}
+
+        List<Hit<ObjectNode>> hits = searchResponse.hits().hits();
+
+        List<Map<String, Object>> list = new ArrayList<>(hits.size());
+        for (Hit<ObjectNode> hit : hits) {
+            ObjectNode node = hit.source();
+            Map<String, Object> map = objectNode2Map(hit.index(), node);
+            map.put("index", hit.index());
+            map.put("highlight", hit.highlight());
+            list.add(map);
+
+            //输出结果日志
+            String line = "=>";
+            for(Map.Entry<String, Object> entry : map.entrySet()){
+                line += "  "+entry.getKey()
+                        +":"+ (entry.getValue()==null?"null":entry.getValue().toString());
+            }
+            System.out.println(line);
+        }
+        return list;
+    }
+
+    public String subFieldIndex(String index, String fieldName){
+        if(fieldName.startsWith(index) && fieldName.length()> index.length()+1) return fieldName.substring(index.length()+1);
+        return fieldName;
+    }
+
+    public Map<String, Object> objectNode2Map(String index, ObjectNode objectNode) {
+        if (null == objectNode) {return new HashMap<>(0);}
+        if (objectNode.isEmpty()) {return new HashMap<>(0);}
+        ObjectMapper objectMapper = new ObjectMapper();
+        Map<String, Object> map = objectMapper.convertValue(objectNode, new TypeReference<Map<String, Object>>() {});
+
+        for(Map.Entry<String, Object> entry : map.entrySet()){
+            String name = subFieldIndex(index, entry.getKey());
+            if(name.equals(entry.getKey())) continue;
+
+            map.remove(entry.getKey());
+            map.put(name, entry.getValue());
+        }
+
+        return map;
+    }
+}

+ 11 - 0
src/main/java/com/bowintek/practice/services/service/EsQueryService.java

@@ -0,0 +1,11 @@
+package com.bowintek.practice.services.service;
+
+import co.elastic.clients.elasticsearch.indices.AnalyzeResponse;
+import com.bowintek.practice.vo.Analyze.ComparisonResult;
+
+import java.util.List;
+import java.util.Map;
+
+public interface EsQueryService {
+    Map<String, Object> query(String text, int page, int limit);
+}

+ 2 - 1
vue/src/views/position/index.vue

@@ -245,7 +245,8 @@ export default defineComponent({
     };
     const add = () => {
       //tabsViewStore.addTabByPath('/position/edit', {});
-      tabsViewStore.addTabByPath('/query/index', {tempId: 'af029fdd-62ca-443e-9503-f940f40a7fdc'});
+      //tabsViewStore.addTabByPath('/query/index', {tempId: 'af029fdd-62ca-443e-9503-f940f40a7fdc'});
+
     };
     const edit = (key: string) => {
       tabsViewStore.addTabByPath('/position/edit', {id: key});

+ 21 - 46
vue/src/views/position/test.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="card-search">
-<!--    <a-divider orientation="left">历史搜索使用方式</a-divider>
+    <a-divider orientation="left">历史搜索使用方式</a-divider>
     <a-form ref="formRef" name="advanced_search" class="ant-advanced-search-form"
             :model="formState"
             @finish="onFinish">
@@ -10,19 +10,19 @@
             name="keyString"
             label="关键字"
             :label-col="{span:3}">
-            &lt;!&ndash;AutoComplete继承至vue&ndash;&gt;
+            <!--AutoComplete继承至vue-->
             <QueryHistoryComplete ref="queryHistoryComplete" v-model:value="formState.keyString"></QueryHistoryComplete>
           </a-form-item>
         </a-col>
         <a-col  :span="6" style="text-align: left">
-          <a-button type="primary" html-type="submit" @click="onFinish">查询</a-button>
+          <a-button type="primary" html-type="submit">查询</a-button>
         </a-col>
       </a-row>
     </a-form>
 
     <a-divider orientation="left">热门搜索使用方式,实际应用改样式即可</a-divider>
     <div style="width: 600px;">
-      &lt;!&ndash;热门搜索历史使用示例,实际应用改样式即可&ndash;&gt;
+      <!--热门搜索历史使用示例,实际应用改样式即可-->
       <QueryHistoryList ref="queryHistoryList" :maxRows="20"></QueryHistoryList>
     </div>
 
@@ -32,9 +32,9 @@
         <template #bodyCell="{ column, text }">
           <template v-if="column.dataIndex === 'chart'">
             <div style="height:40px">
-              &lt;!&ndash;列表单元格中显示曲线图,数据需要根据业务库整理&ndash;&gt;
-              &lt;!&ndash;timeType day month year&ndash;&gt;
-              &lt;!&ndash;dataType gas oil&ndash;&gt;
+              <!--列表单元格中显示曲线图,数据需要根据业务库整理-->
+              <!--timeType day month year-->
+              <!--dataType gas oil-->
               <ChartCell :timeType="('month')" :dataType="('oil')" :wellId="('吉45-144(A2)')" :lineColor="('#FF0000')"></ChartCell>
             </div>
           </template>
@@ -50,11 +50,7 @@
     <a-divider orientation="left">地图</a-divider>
     <div style="width:1000px;height: 400px">
       <ChartMap :wellId="('吉45-144(A2)')"></ChartMap>
-    </div>-->
-    <vue-office-excel src="https://501351981.github.io/vue-office/examples/dist/static/test-files/test.xlsx" style="height: 100vh;" @error="rendered"/>
-    <vue-office-pdf src="https://501351981.github.io/vue-office/examples/dist/static/test-files/test.pdf" @error="rendered" style="width: 100%; height: 100%"/>
-<!--    <vue-office-docx src="https://501351981.github.io/vue-office/examples/dist/static/test-files/test.docx" class="docx-calss" />
-    <vue-pdf-app :config="config" style="height: 100vh;" pdf="/api/wellInfo/downFile?isShow=1&fileName=1.pdf"></vue-pdf-app>-->
+    </div>
   </div>
 </template>
 
@@ -66,42 +62,18 @@ import QueryHistoryComplete from '@/components/basic/querylog/history-complete.v
 import ChartCell from '@/components/basic/chart/chart-cell.vue'
 import ChartProdDynmics from '@/components/basic/chart/chart-prod-dynamics.vue'
 import ChartMap from '@/components/basic/chart/chart-map.vue'
-//import VuePdfApp from "vue3-pdf-app";
-// import this to use default icons for buttons
-//import "vue3-pdf-app/dist/icons/main.css";
-import {handleloadByGet} from "@/utils/downloadFile";
-//引入VueOfficeDocx组件
-import VueOfficeDocx from '@vue-office/docx'
-//引入相关样式
-import '@vue-office/docx/lib/index.css'
-
-import VueOfficePdf from '@vue-office/pdf'
-//引入VueOfficeExcel组件
-import VueOfficeExcel from '@vue-office/excel'
-//引入相关样式
-import '@vue-office/excel/lib/index.css'
+import {get} from "@/api/common";
 
 export default defineComponent({
   name: 'QueryTest',
-  components: {QueryHistoryList, QueryHistoryComplete, ChartCell,
-    ChartProdDynmics,ChartMap,VueOfficeDocx,VueOfficePdf,VueOfficeExcel},
+  components: {QueryHistoryList, QueryHistoryComplete, ChartCell, ChartProdDynmics, ChartMap},
   setup() {
     const route = useRoute();
     const queryHistoryComplete = ref<typeof QueryHistoryComplete>();
     const formState = ref({
       keyString: ""
     });
-    const config = {
-      sidebar: false,
-      secondaryToolbar: false,
-      toolbar: false,
-      errorWrapper: false,
-    };
-    const fileUrl=ref('');
 
-    handleloadByGet( "/api/wellInfo/downFile", {fileId: 'fileId'}, "下载失败!").then(res=>{
-      fileUrl.value=res.link;
-    })
     console.log(route, formState);
 
     watch(formState.value, async (newQuestion) => {
@@ -109,8 +81,14 @@ export default defineComponent({
     })
 
     const onFinish = () => {
-      //记录搜索关键字日志
-      (queryHistoryComplete.value as any).saveHistory(formState.value.keyString);
+      if(true || formState.value.keyString && formState.value.keyString.trim().length>0) {
+        //记录搜索关键字日志
+        (queryHistoryComplete.value as any).saveHistory(formState.value.keyString);
+        //查询搜索结果
+        get('esquery/getQuery', {text: formState.value.keyString, page:0, limit:100}).then(result => {
+          console.log(result);
+        });
+      }
     };
 
     const columns = [
@@ -126,17 +104,14 @@ export default defineComponent({
       { key: '2', name: 'Jim Green', age: 42, address: 'London No. 2 Lake Park, London No. 2 Lake Park', tags: ['loser']},
       { key: '3', name: 'Joe Black', age: 32, address: 'Sidney No. 1 Lake Park, Sidney No. 1 Lake Park', tags: ['cool', 'teacher']},
     ];
-    const rendered=(ex)=>
-    {
-      console.log("渲染完成",ex);
-    }
+
     return {
       formState,
       onFinish,
       queryHistoryComplete,
-      rendered,
+
       columns,
-      data,fileUrl,config
+      data
     };
   }
 });

+ 143 - 0
vue/src/views/position/test2.vue

@@ -0,0 +1,143 @@
+<template>
+  <div class="card-search">
+<!--    <a-divider orientation="left">历史搜索使用方式</a-divider>
+    <a-form ref="formRef" name="advanced_search" class="ant-advanced-search-form"
+            :model="formState"
+            @finish="onFinish">
+      <a-row :gutter="24">
+        <a-col :span="12">
+          <a-form-item
+            name="keyString"
+            label="关键字"
+            :label-col="{span:3}">
+            &lt;!&ndash;AutoComplete继承至vue&ndash;&gt;
+            <QueryHistoryComplete ref="queryHistoryComplete" v-model:value="formState.keyString"></QueryHistoryComplete>
+          </a-form-item>
+        </a-col>
+        <a-col  :span="6" style="text-align: left">
+          <a-button type="primary" html-type="submit" @click="onFinish">查询</a-button>
+        </a-col>
+      </a-row>
+    </a-form>
+
+    <a-divider orientation="left">热门搜索使用方式,实际应用改样式即可</a-divider>
+    <div style="width: 600px;">
+      &lt;!&ndash;热门搜索历史使用示例,实际应用改样式即可&ndash;&gt;
+      <QueryHistoryList ref="queryHistoryList" :maxRows="20"></QueryHistoryList>
+    </div>
+
+    <a-divider orientation="left">列表单元格中显示简单的曲线图</a-divider>
+    <div style="width:1000px;">
+      <a-table :columns="columns" :data-source="data">
+        <template #bodyCell="{ column, text }">
+          <template v-if="column.dataIndex === 'chart'">
+            <div style="height:40px">
+              &lt;!&ndash;列表单元格中显示曲线图,数据需要根据业务库整理&ndash;&gt;
+              &lt;!&ndash;timeType day month year&ndash;&gt;
+              &lt;!&ndash;dataType gas oil&ndash;&gt;
+              <ChartCell :timeType="('month')" :dataType="('oil')" :wellId="('吉45-144(A2)')" :lineColor="('#FF0000')"></ChartCell>
+            </div>
+          </template>
+        </template>
+      </a-table>
+    </div>
+
+    <a-divider orientation="left">Grid类型的图表</a-divider>
+    <div style="width:1200px;">
+      <ChartProdDynmics :wellId="('吉45-144(A2)')"></ChartProdDynmics>
+    </div>
+
+    <a-divider orientation="left">地图</a-divider>
+    <div style="width:1000px;height: 400px">
+      <ChartMap :wellId="('吉45-144(A2)')"></ChartMap>
+    </div>-->
+    <vue-office-excel src="https://501351981.github.io/vue-office/examples/dist/static/test-files/test.xlsx" style="height: 100vh;" @error="rendered"/>
+    <vue-office-pdf src="https://501351981.github.io/vue-office/examples/dist/static/test-files/test.pdf" @error="rendered" style="width: 100%; height: 100%"/>
+<!--    <vue-office-docx src="https://501351981.github.io/vue-office/examples/dist/static/test-files/test.docx" class="docx-calss" />
+    <vue-pdf-app :config="config" style="height: 100vh;" pdf="/api/wellInfo/downFile?isShow=1&fileName=1.pdf"></vue-pdf-app>-->
+  </div>
+</template>
+
+<script  lang="ts">
+import {ref,defineComponent,watch} from "vue";
+import { useRoute} from 'vue-router';
+import QueryHistoryList from '@/components/basic/querylog/history-list.vue'
+import QueryHistoryComplete from '@/components/basic/querylog/history-complete.vue'
+import ChartCell from '@/components/basic/chart/chart-cell.vue'
+import ChartProdDynmics from '@/components/basic/chart/chart-prod-dynamics.vue'
+import ChartMap from '@/components/basic/chart/chart-map.vue'
+//import VuePdfApp from "vue3-pdf-app";
+// import this to use default icons for buttons
+//import "vue3-pdf-app/dist/icons/main.css";
+import {handleloadByGet} from "@/utils/downloadFile";
+//引入VueOfficeDocx组件
+import VueOfficeDocx from '@vue-office/docx'
+//引入相关样式
+import '@vue-office/docx/lib/index.css'
+
+import VueOfficePdf from '@vue-office/pdf'
+//引入VueOfficeExcel组件
+import VueOfficeExcel from '@vue-office/excel'
+//引入相关样式
+import '@vue-office/excel/lib/index.css'
+
+export default defineComponent({
+  name: 'QueryTest',
+  components: {QueryHistoryList, QueryHistoryComplete, ChartCell,
+    ChartProdDynmics,ChartMap,VueOfficeDocx,VueOfficePdf,VueOfficeExcel},
+  setup() {
+    const route = useRoute();
+    const queryHistoryComplete = ref<typeof QueryHistoryComplete>();
+    const formState = ref({
+      keyString: ""
+    });
+    const config = {
+      sidebar: false,
+      secondaryToolbar: false,
+      toolbar: false,
+      errorWrapper: false,
+    };
+    const fileUrl=ref('');
+
+    handleloadByGet( "/api/wellInfo/downFile", {fileId: 'fileId'}, "下载失败!").then(res=>{
+      fileUrl.value=res.link;
+    })
+    console.log(route, formState);
+
+    watch(formState.value, async (newQuestion) => {
+      console.log("formState", newQuestion);
+    })
+
+    const onFinish = () => {
+      //记录搜索关键字日志
+      (queryHistoryComplete.value as any).saveHistory(formState.value.keyString);
+    };
+
+    const columns = [
+      { title: 'Name', dataIndex: 'name', key: 'name', },
+      { title: 'Age', dataIndex: 'age', key: 'age', width: 80, },
+      { title: 'Address', dataIndex: 'address', key: 'address 1', ellipsis: true, },
+      { title: 'Long Column Long Column Long Column', dataIndex: 'address', key: 'address 2', ellipsis: true},
+      { title: 'ChartCell', dataIndex: 'chart', key: 'ChartCell', width:160}
+    ];
+
+    const data = [
+      { key: '1', name: 'John Brown', age: 32, address: 'New York No. 1 Lake Park, New York No. 1 Lake Park', tags: ['nice', 'developer']},
+      { key: '2', name: 'Jim Green', age: 42, address: 'London No. 2 Lake Park, London No. 2 Lake Park', tags: ['loser']},
+      { key: '3', name: 'Joe Black', age: 32, address: 'Sidney No. 1 Lake Park, Sidney No. 1 Lake Park', tags: ['cool', 'teacher']},
+    ];
+    const rendered=(ex)=>
+    {
+      console.log("渲染完成",ex);
+    }
+    return {
+      formState,
+      onFinish,
+      queryHistoryComplete,
+      rendered,
+      columns,
+      data,fileUrl,config
+    };
+  }
+});
+</script>