啥也不会的实习生:语音数据分词可视化模块(SSM+Vue)

前言

具体还是基于上篇功能的后续模块开发,将数据库的语音数据分词后,实现关键词统计功能,再将统计的结果以柱状图的形式可视化(只显示次数多的前20条关键词)

数据库表:

分词前原表tb_keyword

分词后表tb_word(flag是词性,parentid是父节点id)

前端最终实现效果:

1.可以根据词性与关键词条件筛选

2.可以实现统计功能,统计关键词出现的次数(次数多的前20个)

3.统计结果柱状图显示

 

 ​​​​​​​

 分词功能的实现(部分)

分词模块主要使用的是jieba分词,在后端pom文件中加入jieba分词依赖

<!-- jiba依赖-->
        <dependency>
            <groupId>com.huaban</groupId>
            <artifactId>jieba-analysis</artifactId>
            <version>1.0.2</version>
        </dependency>

 功能实现主要代码(仅供参考)

package com.chery.quartz.task;

import com.chery.common.utils.StringUtils;
import com.chery.web.mychery.domain.TbKeyword;
import com.chery.web.mychery.domain.TbWord;
import com.chery.web.mychery.service.ITbKeywordService;
import com.chery.web.mychery.service.ITbWordService;
import com.huaban.analysis.jieba.JiebaSegmenter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 定时任务调度测试
 *
 * @author chery
 */
@Component("WordTask")
public class WordTask {
    @Autowired
    private ITbKeywordService tbKeywordService;

    @Autowired
    public ITbWordService tbWordService;

    private Object TbWord;

    private static WordTask KeyWordTask;

    public WordTask(ITbWordService tbWordService) {
        this.tbWordService = tbWordService;
    }

    @PostConstruct
    public void init() {
        KeyWordTask = this;
        KeyWordTask.tbWordService = this.tbWordService;
        KeyWordTask.tbKeywordService = this.tbKeywordService;
    }

    public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i) {
        System.out.println(StringUtils.format("执行多参方法: 字符串类型{},布尔类型{},长整型{},浮点型{},整形{}", s, b, l, d, i));
    }

    public void ryParams(String params) {

        System.out.println("执行有参方法:" + params);
    }

    public void ComputerKeyWord() {

        List<TbKeyword> tbKeywords = KeyWordTask.tbKeywordService.selectTbKeywordList(new TbKeyword());
        JiebaSegmenter jiebaSegmenter = new JiebaSegmenter();
        Map<String, Integer> map = new HashMap<>();
        //分词
        tbKeywords.forEach(item -> {
            String content = item.getContent();
            if (StringUtils.isNotEmpty(content)
            ) {
                List<String> contents = jiebaSegmenter.sentenceProcess(content);
                contents.forEach(word -> {
                    TbWord tbWord = new TbWord();
                    tbWord.setWords(word);
//            tbWord.setWords("entry");
//            TbWordMapper<TbKeyword> tbWordService = null;
                    int resultFlag = KeyWordTask.tbWordService.insertTbWord(tbWord);
                    System.out.println(word);

//
//                    }
                });
            }
        });
        //排序
//        LinkedHashMap<String, Integer> result = map.entrySet().stream()
//                .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
//                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue,
//                        LinkedHashMap::new));
//        System.out.println("----------------结果集-------------------------");
//        System.out.println(result);
//        System.out.println("---------------返回前20的词-----------------------");
//        AtomicInteger atomicInteger = new AtomicInteger(0);
//        for (Map.Entry<String, Integer> entry : result.entrySet()) {
//            TbWord tbWord = new TbWord();
//            tbWord.setWords(entry.getKey());
            tbWord.setWords("entry");
            TbWordMapper<TbKeyword> tbWordService = null;
//            List<TbWord> tbwords = KeyWordTask.tbWordService.insertTbWordList(tbWord);
//            System.out.println(entry.getKey());
//            TbWord = entry;
//            tbWord.setWords("entry");
//            atomicInteger.incrementAndGet();
//            if (atomicInteger.get() == 20) {
//                break;
//
//            }
//        }
//
//
        TbWord tbWord = new TbWord();
            TbWordMapper<TbKeyword> tbWordService = null;
            List<TbWord> tbwords = tbWordService.insertTbWordList(tbWord);
//
//        System.out.println("-----------------结束-----------------------");

    }


}


//            TbWord tbWord = new TbWord();
//            TbWordMapper<TbKeyword> tbWordService = null;
//            List<TbWord> tbwords = tbWordService.insertTbWordList(tbWord);
//            System.out.println(TbWord);

 后端代码

和上一篇文章基本一致,唯一不同的是在mapper层的配置文件.xml中加一个只获取前20条关键词次数的限制

前端代码

在上篇文章实现统计功能的基础上,实现将统计结果数据以柱状图方式显示

新建一个文件夹analyse ,创建两个vue文件实现功能

index.vue

<template>
 <el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
      <line-chart :chart-data="lineChartData" />
    </el-row>
</template>

<script>
import {listWordCount} from "@/api/mychery/word";
import LineChart from './LineChart'

var Yword=[]
var Ywordnum=[]
const ChartData = {
  linedata: {
    actualData: Yword,
    expectedData: Ywordnum
  }
}
export default {
  name: "Word",
  data() {
    return {
      // 统计参数
      total: 0,
      lineChartData: ChartData.linedata,
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        words: undefined,
        count: undefined,
      }
    };
  },
  components: {
    LineChart
  },
  created() {
     this.getlist();
  },

  methods: {
    getlist(){
      listWordCount(this.queryParams).then((response) => {
       for(var i  in response){
          var word=response[i].words
          var wordnum=response[i].count
          Yword.push(word)
          Ywordnum.push(wordnum)
        }
      });
    },
   handleQuery() {
      this.getcountList();
    },
    resetQuery() {
      this.dateRange = [];
      this.resetForm("queryForm");
      this.handleQuery();
    },
    handleSetLineChartData(type) {
      this.$emit('handleSetLineChartData', type)
    }
  },
   beforeDestroy(){
   clearInterval(this.timer);        
   this.timer = null;
 }
};
</script>

LineChart.vue

<template>
  <div :class="className" :style="{height:height,width:width}" />
</template>

<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme // D:\Documents and Settings\20023998\桌面\chery_prj\chery-master\chery-ui\src\views\dash\mixins
import resize from '@/views/dash/mixins/resize'

export default {
  mixins: [resize],
  props: {
    className: {
      type: String,
      default: 'chart'
    },
    width: {
      type: String,
      default: '100%'
    },
    height: {
      type: String,
      default: '600px'
    },
    autoResize: {
      type: Boolean,
      default: true
    },
    chartData: {
      type: Object,
      required: true
    }
  },
  data() {
    return {
      loading: true,
      exportLoading: false,
      chart: null
    }
  },
  watch: {
    chartData: {
      deep: true,
      handler(val) {
        this.setOptions(val)
      }
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.initChart()
    })
  },
  beforeDestroy() {
    if (!this.chart) {
      return
    }
    this.chart.dispose()
    this.chart = null
    
  },
  created() {
    this.fun()
  },
  methods: {
    initChart() {
      this.chart = echarts.init(this.$el, 'macarons')
      this.setOptions(this.chartData)
    },
    fun(){
     let timer = setInterval(()=>{
        this.initChart()  
      },1000*60*3);
      this.$once('hook:beforeDestroy',()=>{
        clearInterval(timer);
        timer = null;
      })
    },
    setOptions({ actualData, expectedData} = {}) {
      // console.log(actualData, expectedData)
      this.chart.setOption({
        title:{
          text:'关键词',
          x:'center'
          },
        xAxis: {
          axisTick: {
            show: false
          },
          type: 'category',
          data: actualData,
          boundaryGap: true
        },
        
        grid: {
          left: 0,
          right: 10,
          bottom: 40,
          top: 30,
          containLabel: true
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'cross'
          },
          padding: [5, 10]
        },
        yAxis: [{
          axisTick: {
            show: false
          }
        },
        {
          type: 'value'
        }
      ],
        color:  ['#0000FF','#8A2BE2'],
        legend: {
          x:'right',
          data: ['生产'],
         }, 
        series: [{
          name: '生产', 
          smooth: true,
          type: 'bar',
          data: expectedData,
          animationDuration: 1800,
          animationEasing: 'cubicInOut',

          itemStyle: {
            normal: {
                label: {
                    show: true, //开启显示
                    position: 'top', //在上方显示//新增运营
                    textStyle: { //数值样式
                        color: '#0000FF',
                        fontSize: 12
                    }
                }
            }
          }
        }
        ]
          
      })
    }
  }
}
</script>

引用的js文件

word.js

import request from '@/utils/request'

//统计
export function listWordCount(analyse) {
  return request({
    url: '/mychery/word/analyse',
    method: 'get',
    params: analyse
  })
} 


// 查询关键词查询列表
export function listWord(query) {
  return request({
    url: '/mychery/word/list',
    method: 'get',
    params: query
  })
}

// 查询关键词查询详细
export function getWord(id) {
  return request({
    url: '/mychery/word/' + id,
    method: 'get'
  })
}

// 新增关键词查询
export function addWord(data) {
  return request({
    url: '/mychery/word',
    method: 'post',
    data: data
  })
}

// 修改关键词查询
export function updateWord(data) {
  return request({
    url: '/mychery/word',
    method: 'put',
    data: data
  })
}

// 删除关键词查询
export function delWord(id) {
  return request({
    url: '/mychery/word/' + id,
    method: 'delete'
  })
}

// 导出关键词查询
export function exportWord(query) {
  return request({
    url: '/mychery/word/export',
    method: 'get',
    params: query
  })
}

 resize.js

import { debounce } from '@/utils'

export default {
  data() {
    return {
      $_sidebarElm: null,
      $_resizeHandler: null
    }
  },
  mounted() {
    this.initListener()
  },
  activated() {
    if (!this.$_resizeHandler) {
      // avoid duplication init
      this.initListener()
    }

    // when keep-alive chart activated, auto resize
    this.resize()
  },
  beforeDestroy() {
    this.destroyListener()
  },
  deactivated() {
    this.destroyListener()
  },
  methods: {
    // use $_ for mixins properties
    // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
    $_sidebarResizeHandler(e) {
      if (e.propertyName === 'width') {
        this.$_resizeHandler()
      }
    },
    initListener() {
      this.$_resizeHandler = debounce(() => {
        this.resize()
      }, 100)
      window.addEventListener('resize', this.$_resizeHandler)

      this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
      this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
    },
    destroyListener() {
      window.removeEventListener('resize', this.$_resizeHandler)
      this.$_resizeHandler = null

      this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
    },
    resize() {
      const { chart } = this
      chart && chart.resize()
    }
  }
}

出现问题

每刷新切换一次页面会重复获取数据图

 问题解决

引入dedupe的js文件

vehicle.js

export function Str2Byte (str) {
    var pos = 0
    var len = str.length
    // eslint-disable-next-line eqeqeq
    if (len % 2 != 0) { return null }
    len /= 2
    var hexA = []
    for (var i = 0; i < len; i++) {
      var s = str.substr(pos, 2)
      var v = parseInt(s, 16)
      hexA.push(v)
      pos += 2
    }
    return hexA
  }

  export function hex2int (hex) {
    var len = hex.length
    var a = new Array(len)
    var code
    for (var i = 0; i < len; i++) {
      code = hex.charCodeAt(i)
      if (code >= 48 && code < 58) {
        code -= 48
      } else {
        code = (code & 0xdf) - 65 + 10
      }
      a[i] = code
    }
    return a.reduce(function (acc, c) {
      acc = 16 * acc + c
      return acc
    }, 0)
  }

  export function hex2ascill (str) {
    var arr = str.split('')
    var obj = ''
    for (var i = 0; i < arr.length / 2; i++) {
      var tmp = '0x' + arr[i * 2] + arr[i * 2 + 1]
      var charValue = String.fromCharCode(tmp)
      obj += charValue
    }
    return obj
  }

  export function arr2number (str) {
    var arr = ''
    for (var j = 0; j < str.length; j++) {
      arr += str[j]
    }
    return arr
  }

  export function average (str) {
    var sum = 0
    var arr = 0
    for (var i = 0; i < str.length; i++) {
      sum += str[i]
    }
    arr = sum / str.length
    return arr
  }

  export function Max (arr) {
    let max = arr[0]
    for (let i = 0; i < arr.length - 1; i++) {
      max = max < arr[i + 1] ? arr[i + 1] : max
    }
    return max
  }

  export function Min (arr) {
    let min = arr[0]
    for (let i = 0; i < arr.length; i++) {
      min = min > arr[i + 1] ? arr[i + 1] : min
    }
    return min
  }

  export function del(arr){
    var str = []; 
    for(var i = 0,len = arr.length;i < len;i++){ 
    ! RegExp(arr[i],"g").test(str.join(",")) && (str.push(arr[i])); 
    }  
    return str
  }

  export function dedupe(array){
    return Array.from(new Set(array));
  }

  export function group(array, subGroupLength) {
  let index = 0;
  let newArray = [];
  var subGroupLength=2
  while(index < array.length) {
      newArray.push(array.slice(index, index += subGroupLength));
  }
  return newArray;
}

export function subtract(array){
let str = [];
	for(let i in array){
	    if(i>0){
		    str.push(array[i]-array[i-1])
		}
	}
  return str;
}

//
 export function isContinuityArray(arr) {
  //var isContinuityArray = true;
  for(var i=0;i<arr.length;i++) {
      if(arr[i]<=arr[i+1]){
          var isContinuityArray = true;
      }else if(arr[i]>arr[i+1]){
          var isContinuityArray = false;
      }
  }
  return isContinuityArray;
}

//查找目标位置
export function findAllOccurrences(arr, target) {
  for(var i=0;i<arr.length;i++)
      {
          if(target===arr[i])
              {
                 return i
              }
      }

}

//获取最大数值位置
export function getMaxIndex(arr) {
  var max = arr[0];
  //声明了个变量 保存下标值
  var index = 0;
  for (var i = 0; i < arr.length; i++) {
      if (max < arr[i]) {
          max = arr[i];
          index = i;
      }
  }
  return index;
}

修改后的index.vue

<template>
 <el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
      <line-chart :chart-data="lineChartData" />
    </el-row>
</template>

<script>
import {listWordCount} from "@/api/mychery/word";
import LineChart from './LineChart'

var Yword=[]
var Ywordnum=[]
const ChartData = {
  linedata: {
    actualData: Yword,
    expectedData: Ywordnum
  }
}
export default {
  name: "Word",
  data() {
    return {
      // 统计参数
      total: 0,
      lineChartData: ChartData.linedata,
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        words: undefined,
        count: undefined,
      }
    };
  },
  components: {
    LineChart
  },
  created() {
     this.getlist();
     this.fun();
  },

  methods: {
    fun(){
     let timer = setInterval(()=>{
        this.initChart()  
      },1000*60*3);
      this.$once('hook:beforeDestroy',()=>{
        clearInterval(timer);
        timer = null;
      })
    },
    getlist(){
      listWordCount(this.queryParams).then((response) => {
       for(var i  in response){
          var word=response[i].words
          var wordnum=response[i].count
          Yword.push(word)
          Ywordnum.push(wordnum)
        }
      });
    },
   handleQuery() {
      this.getcountList();
    },
    resetQuery() {
      this.dateRange = [];
      this.resetForm("queryForm");
      this.handleQuery();
    },
    handleSetLineChartData(type) {
      this.$emit('handleSetLineChartData', type)
    }
  },
   beforeDestroy(){
   clearInterval(this.timer);        
   this.timer = null;
 }
};
</script>

修改后的LineChart.vue

<template>
  <div :class="className" :style="{height:height,width:width}" />
</template>

<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme // D:\Documents and Settings\20023998\桌面\chery_prj\chery-master\chery-ui\src\views\dash\mixins
import resize from '@/views/dash/mixins/resize'
import {dedupe} from '@/api/datatools/dataplayback/vehicle.js'


export default {
  mixins: [resize],
  props: {
    className: {
      type: String,
      default: 'chart'
    },
    width: {
      type: String,
      default: '100%'
    },
    height: {
      type: String,
      default: '600px'
    },
    autoResize: {
      type: Boolean,
      default: true
    },
    chartData: {
      type: Object,
      required: true
    }
  },
  data() {
    return {
      loading: true,
      exportLoading: false,
      chart: null
    }
  },
  watch: {
    chartData: {
      deep: true,
      handler(val) {
        this.setOptions(val)
      }
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.initChart()
    })
    if (this.timer) {
          clearInterval(this.timer)
      } else {
          this.timer = setInterval(() => {
            setTimeout(this.getList(), 0)
          }, 60000*3)
      }
  },
  beforeDestroy() {
    if (!this.chart) {
      return
    }
    this.chart.dispose()
    this.chart = null
    
  },
  created() {
    // this.fun()
  },
  methods: {
    initChart() {
      this.chart = echarts.init(this.$el, 'macarons')
      this.setOptions(this.chartData)
    },
    // fun(){
    //  let timer = setInterval(()=>{
    //     this.initChart()  
    //   },1000*60*3);
    //   this.$once('hook:beforeDestroy',()=>{
    //     clearInterval(timer);
    //     timer = null;
    //   })
    // },
    setOptions({ actualData, expectedData} = {}) {
      // console.log(actualData, expectedData)
      this.chart.setOption({
        title:{
          text:'关键词统计图',
          x:'center'
          },
        xAxis: {
          axisTick: {
            show: false
          },
          type: 'category',
          data: dedupe(actualData),
          boundaryGap: true
        },
        
        grid: {
          left: 0,
          right: 10,
          bottom: 40,
          top: 30,
          containLabel: true
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'cross'
          },
          padding: [5, 10]
        },
        yAxis: [{
          axisTick: {
            show: false
          }
        },
        {
          type: 'value'
        }
      ],
        color:  ['#0000FF','#8A2BE2'],
        legend: {
          x:'right',
          data: ['次数'],
         }, 
        series: [{
          name: '次数', 
          smooth: true,
          type: 'bar',
          data: expectedData,
          animationDuration: 1800,
          animationEasing: 'cubicInOut',

          itemStyle: {
            normal: {
                label: {
                    show: true, //开启显示
                    position: 'top', //在上方显示//新增运营
                    textStyle: { //数值样式
                        color: '#0000FF',
                        fontSize: 12
                    }
                }
            }
          }
        }
        ]
          
      })
    }
  }
}
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kong清空

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值