当前位置: 首页 > news >正文

快捷做网站汕头seo外包机构

快捷做网站,汕头seo外包机构,cms203片,网站页面设计考虑要素❣博主主页: 33的博客❣ ▶️文章专栏分类:项目日记◀️ 🚚我的代码仓库: 33的代码仓库🚚 🫵🫵🫵关注我带你了解更多项目内容 目录 1.前言2.索引结构2.1创捷索引2.2根据索引查询2.3新增文档2.4内存索引保存到磁盘2.5把…

❣博主主页: 33的博客❣
▶️文章专栏分类:项目日记◀️
🚚我的代码仓库: 33的代码仓库🚚
🫵🫵🫵关注我带你了解更多项目内容

在这里插入图片描述

目录

  • 1.前言
  • 2.索引结构
    • 2.1创捷索引
    • 2.2根据索引查询
    • 2.3新增文档
    • 2.4内存索引保存到磁盘
    • 2.5把磁盘索引加载到内存
  • 3.性能优化
    • 3.1多线程
    • 3.2线程安全
    • 3.3CountDownLatch类
  • 4.总结

1.前言

在上一篇文章中,我们已经介绍了索引解析,那么接下来我们继续完善我们的项目,既然已经有了解析好的索引,那么我们就需要把解析的内容添加到倒排索引和正排索引中。

2.索引结构

创建index类,通过这个类来构建索引结构
基本步骤:

  • 用ArrayList创建正排索引
  • 用HashMap创建倒排索引
  • 1.给定docid在正排索引中,查询详细信息
  • 2.给定一个词,在倒排索引中查与这个词的关联文档
  • 3.往索引中新增文档
  • 4.把内存的索引保存到磁盘
  • 5.把磁盘的索引结构保存到内存

2.1创捷索引

正排索引

private ArrayList<DocInfo> forwardIndex=new ArrayList<>();

倒排索引

private HashMap<String,ArrayList<Weight>> invertedIndex=new HashMap<>();

DocInfo类:

public class DocInfo {private int docID;private String title;private String url;private String content;public int getDocID() {return docID;}public void setDocID(int docID) {this.docID = docID;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}
}

Weight类:

public class Weight {private int docId;private int weight;public int getDocId() {return docId;}public void setDocId(int docId) {this.docId = docId;}public int getWeight() {return weight;}public void setWeight(int weight) {this.weight = weight;}
}

2.2根据索引查询

//1.根据docId查询文档详情,数组小标就是文档idpublic DocInfo getDocInfo(int docId){return forwardIndex.get(docId);}
//2.给定一个词,查在哪些文档中public List<Weight> getInverted(String term){return invertedIndex.get(term);}   

2.3新增文档

 public void addDoc(String title,String url,String content){//给正排索引新增和倒排索引都新增信息//构建正排索引DocInfo docInfo=buildForward(title,url,content);//创建倒排索引buildInverted(docInfo);}

在正排索引中添加文档:

private DocInfo buildForward(String title, String url, String content) {DocInfo docInfo=new DocInfo();docInfo.setTitle(title);docInfo.setUrl(url);docInfo.setContent(content);//巧妙设计:docInfoId的下标和数组下标一一对应docInfo.setDocID(forwardIndex.size());forwardIndex.add(docInfo);return docInfo;}

在倒排索引中新增文档
1.需要统计每一个词在文档中的出现次数,在根据次数算出权重
2.首先进行分词操作,统计每一个不同的词在标题中出现的次数
3.再进行分词操作,统计每一个词在正文出现的次数
4.设置权重为标题次数*10+正文次数

 private void buildInverted(DocInfo docInfo) {class WordCnt{public int titleCount;public int contentCount;}HashMap<String,WordCnt> wordCntHashMap=new HashMap<>();//1.针对标题进行分词操作List<Term> terms= ToAnalysis.parse(docInfo.getTitle()).getTerms();//2.针对分词结果,统计每个词出现的次数for (Term term:terms){String word=term.getName();WordCnt wordCnt=wordCntHashMap.get(word);if (wordCnt==null){WordCnt newwordCnt=new WordCnt();newwordCnt.titleCount=1;newwordCnt.contentCount=0;wordCntHashMap.put(word,newwordCnt);}else {wordCnt.titleCount+=1;}}//3.针对正文进行分词操作List<Term> terms2=ToAnalysis.parse(docInfo.getContent()).getTerms();//4.遍历分词结果,统计每个词出现的次数for (Term term:terms2){String word=term.getName();WordCnt wordCnt=wordCntHashMap.get(word);if (wordCnt==null){WordCnt newWordCnt=new WordCnt();newWordCnt.titleCount=0;newWordCnt.contentCount=1;wordCntHashMap.put(word,newWordCnt);}else {wordCnt.contentCount+=1;}}//5.设置权重为:标题*10+正文//一个对象必须实现了Iterable接口才能使用for each进行遍历,而Map并没有实现该接口,但Set实现了,所以就把Map转换为Setfor(Map.Entry<String,WordCnt> entry:wordCntHashMap.entrySet()) {            List<Weight> invertedList=invertedIndex.get(entry.getKey());if (invertedList==null){ArrayList<Weight> newInvertedList=new ArrayList<>();Weight weight=new Weight();weight.setWeight(entry.getValue().titleCount*10+entry.getValue().contentCount);weight.setDocId(docInfo.getDocID());newInvertedList.add(weight);invertedIndex.put(entry.getKey(),newInvertedList);}else {Weight weight=new Weight();weight.setDocId(docInfo.getDocID());weight.setWeight(entry.getValue().titleCount*10+entry.getValue().contentCount);invertedList.add(weight);}        }}

2.4内存索引保存到磁盘

索引当前是存储在内存中的,构造索引的过程是非常耗时的,因此我们就不应该再服务器启动时才去构造索引,通常就把这些耗时的操作,单独执行完成之后,然后再让线上的服务器加载构造好的索引。
我们就把内存中构造的索引结构,给变成一个字符串,然后写入文件即可,这个操作就叫序列化。适应Jackson中的ObjectMapper来完成此操作。

 private static  String INDEX_PATH="D:/doc_searcher_index/";public void save(){long beg=System.currentTimeMillis();System.out.println("保存索引开始!");File indexPathFile=new File(INDEX_PATH);if(!indexPathFile.exists()){indexPathFile.mkdir();}File forwardIndexFile=new File(INDEX_PATH+"forward.txt");File invertedIndexFile=new File(INDEX_PATH+"inverted.txt");try {//利用ObjectMapperJava对象转换为JSON格式//从内存中读取forwardIndex保存到forwardIndexFileobjectMapper.writeValue(forwardIndexFile,forwardIndex);//从内存中读取nvertedIndex保存到invertedIndexFileforwardIndexFileobjectMapper.writeValue(invertedIndexFile,invertedIndex);}catch (IOException e) {e.printStackTrace();}long end=System.currentTimeMillis();System.out.println("保存索引完成!消耗时间:"+(end-beg)+"ms");}

2.5把磁盘索引加载到内存

public void load(){long beg=System.currentTimeMillis();System.out.println("加载索引开始!");File forwardIndexFile=new File(INDEX_PATH+"forward.txt");File invertedIndexFile=new File(INDEX_PATH+"inverted.txt");try {forwardIndex=objectMapper.readValue(forwardIndexFile, new TypeReference<ArrayList<DocInfo>>() {});invertedIndex=objectMapper.readValue(invertedIndexFile, new TypeReference<HashMap<String, ArrayList<Weight>>>() {});}catch (IOException e){e.printStackTrace();}long end=System.currentTimeMillis();System.out.println("加载引擎结束消耗时间:"+(end-beg)+"ms");}

parser相当于制作索引的入口,对应到一个可执行的程序
index相当于实现了索引的数据结构,提供一些Api
接下来我们就在parser里面调用对应的api
在parser类中解析完Html文件时,应添加到索引中

private  void parseHTML(File f) {//1.解析HTML标题String title=parseTitle(f);//2.解析HTML的URLString url=parseUrl(f);//3.解析HTML的正文long beg=System.nanoTime();//String content=parseContent(f);String content=parseContentByRegex(f);long mid=System.nanoTime();//把解析出来的信息加载到索引index.addDoc(title,url,content);         }

在添加完索引之后,应该把索引保存到磁盘

public void run()  {long beg=System.currentTimeMillis();System.out.println("索引制作开始");//1.枚举出INPUT_PATH下的所有html文件ArrayList<File> fileList=new ArrayList<>();enumFile(INPUT_PATH,fileList);//2.解析文档内容for (File f:fileList){System.out.println("开始解析"+f.getAbsolutePath()+"....");parseHTML(f);}//3.把内存构造的索引保存到磁盘index.save();long end=System.currentTimeMillis();System.out.println("索引制作结束!消耗时间:"+(end-beg)+"ms");}

3.性能优化

此时我们已经完成了文档解析和索引制作模块,那么我们进行验证
在这里插入图片描述
文档内容正确生成:
在这里插入图片描述
在这里插入图片描述
但我们观察索引制作的时间:一个消耗了19973ms就是19s,花费的时间是比较长的,那么有什么办法提高效率呢?方法当然是有的,首先我们得清楚具体是哪一个步骤拖慢了执行效率,我们来分析代码:
在这里插入图片描述
可以看到解析文档的时候从磁盘读文件,循环遍历文件操作,那么显然效率是非常慢的,既然一个线程串行执行效率非常慢,那么我们就采用多线程并发执行来提高效率。

3.1多线程

我们可以使用创建一个线程池来实现并发操作。通过submit往线程池中提价任务,操作极快(只是把Runnable对象放入阻塞队列中)。
把代码改进成多线程的版本,线程池中的线程数目具体设置成多少才合适呢?最好通过实验来确定。

public void run()  {long beg=System.currentTimeMillis();System.out.println("索引制作开始");//1.枚举出INPUT_PATH下的所有html文件ArrayList<File> fileList=new ArrayList<>();enumFile(INPUT_PATH,fileList);ExecutorService executorService= Executors.newFixedThreadPool(6);//2.解析文档内容for (File f:files){executorService.submit(new Runnable() {@Overridepublic void run() {System.out.println("解析:"+f.getAbsolutePath());parseHTML(f);                    }});}//3.把内存构造的索引保存到磁盘index.save();long end=System.currentTimeMillis();System.out.println("索引制作结束!消耗时间:"+(end-beg)+"ms");}

3.2线程安全

我们既然引入了多线程就要考虑线程安全问题,要注意修改操作读写操作。当多个线程同时尝试修改同一个共享数据时,需要确保数据的一致性,避免出现竞态条件。读写操作:如果一个线程在读取共享数据的同时另一个线程在修改该数据,可能导致读取到不一致或无效的数据。
那么我们就需要对程序进行加锁操作:
在这里插入图片描述
在这里插入图片描述

3.3CountDownLatch类

添加锁虽然解决了线程安全问题,依然有新的问题,那就是在所有文件提交完成后就会立即执行save()操作,但是可能文件解析还没有完成。为了解决这样的问题,我们就引入 CountDownLatch类。
CountDownLatch类类似于跑步比赛的裁判,只有所有的选手都撞线了,就认为这场比赛结束了。再构造 CountDownLatch的时候指定一下比赛选手的个数,每个选手撞线都要通知一下countDown(),通过await来等待所有的选手都撞线完毕才执行save()操作。

public void runByThread(){long beg=System.currentTimeMillis();System.out.println("索引开始制作");//1.枚举出INPUT_PATH下的所有html文件ArrayList<File> files=new ArrayList<>();enumFile(INPUT_PATH,files);//2.解析文档内容CountDownLatch latch=new CountDownLatch(files.size());ExecutorService executorService= Executors.newFixedThreadPool(6);for (File f:files){executorService.submit(new Runnable() {@Overridepublic void run() {System.out.println("解析:"+f.getAbsolutePath());parseHTML(f);latch.countDown();}});}try {//await会阻塞,把所有选手都调用countDown以后才会继续执行latch.await();} catch (InterruptedException e) {throw new RuntimeException(e);}//手动的把线程池里面的线程杀掉executorService.shutdown();//3.把内存构造的索引保存到磁盘index.save();long end=System.currentTimeMillis();System.out.println("索引制作结束!消耗时间:"+(end-beg)+"ms");System.out.println("t1:"+t1+"t2"+t2);}

4.总结

这篇文章主要完成了索引制作模块,以及进行了性能优化,在下一篇文章中将进行搜索模块的制作。

下期预告:项目日记(三)


文章转载自:
http://iyft.gtqx.cn
http://bromate.gtqx.cn
http://bachelorship.gtqx.cn
http://scholiast.gtqx.cn
http://meditator.gtqx.cn
http://extraembryonic.gtqx.cn
http://ruddleman.gtqx.cn
http://seaman.gtqx.cn
http://sportive.gtqx.cn
http://schrik.gtqx.cn
http://riotous.gtqx.cn
http://ardent.gtqx.cn
http://chubbiness.gtqx.cn
http://oceanography.gtqx.cn
http://pavid.gtqx.cn
http://pfft.gtqx.cn
http://motel.gtqx.cn
http://cowson.gtqx.cn
http://paranoia.gtqx.cn
http://talocalcaneal.gtqx.cn
http://engaging.gtqx.cn
http://phonemics.gtqx.cn
http://indolently.gtqx.cn
http://piagetian.gtqx.cn
http://clover.gtqx.cn
http://jingo.gtqx.cn
http://lentisk.gtqx.cn
http://differentia.gtqx.cn
http://ventricle.gtqx.cn
http://mortlake.gtqx.cn
http://senusi.gtqx.cn
http://oleic.gtqx.cn
http://superoxide.gtqx.cn
http://caravansarai.gtqx.cn
http://surlily.gtqx.cn
http://rhamnus.gtqx.cn
http://downtonian.gtqx.cn
http://tributyl.gtqx.cn
http://maintopsail.gtqx.cn
http://galliwasp.gtqx.cn
http://milton.gtqx.cn
http://lalophobia.gtqx.cn
http://pothook.gtqx.cn
http://demagogue.gtqx.cn
http://granger.gtqx.cn
http://entrammel.gtqx.cn
http://puzzling.gtqx.cn
http://inaugurate.gtqx.cn
http://raspberry.gtqx.cn
http://worms.gtqx.cn
http://surculi.gtqx.cn
http://consignation.gtqx.cn
http://thruway.gtqx.cn
http://staggard.gtqx.cn
http://spurrite.gtqx.cn
http://reprisal.gtqx.cn
http://veronese.gtqx.cn
http://enframe.gtqx.cn
http://orfe.gtqx.cn
http://prequel.gtqx.cn
http://frighten.gtqx.cn
http://sadza.gtqx.cn
http://directorial.gtqx.cn
http://spurrier.gtqx.cn
http://botchwork.gtqx.cn
http://poughite.gtqx.cn
http://dankly.gtqx.cn
http://etrog.gtqx.cn
http://grasstex.gtqx.cn
http://boxboard.gtqx.cn
http://queerish.gtqx.cn
http://wyse.gtqx.cn
http://conceptualist.gtqx.cn
http://gladiola.gtqx.cn
http://reinsurance.gtqx.cn
http://mephitical.gtqx.cn
http://najaf.gtqx.cn
http://loricate.gtqx.cn
http://reynosa.gtqx.cn
http://guly.gtqx.cn
http://beggardom.gtqx.cn
http://submergence.gtqx.cn
http://catena.gtqx.cn
http://mandrake.gtqx.cn
http://bowstring.gtqx.cn
http://subsaline.gtqx.cn
http://leech.gtqx.cn
http://nardoo.gtqx.cn
http://fanfaron.gtqx.cn
http://rivulet.gtqx.cn
http://artistical.gtqx.cn
http://lanceolate.gtqx.cn
http://cooperative.gtqx.cn
http://piggle.gtqx.cn
http://vinnitsa.gtqx.cn
http://endosternite.gtqx.cn
http://kenyanization.gtqx.cn
http://pneumonia.gtqx.cn
http://hospice.gtqx.cn
http://hithermost.gtqx.cn
http://www.15wanjia.com/news/60236.html

相关文章:

  • c做的网站网络推广培训
  • 如何给英文网站做外链网络广告策划的内容
  • 做网站要属于无形资产吗web成品网站源码免费
  • 免费企业网站建站晚上看b站
  • 怎么查一个网站的外链和反链软件seo是什么意思广东话
  • wordpress 评论者邮箱seo短视频
  • 网站刷新新前台是什么意思郑州高端网站建设哪家好
  • 网站建设手机网络优化工程师为什么都说坑人
  • 建设个人网站流程网站建设制作免费
  • 甘肃网站建设百度seo关键词排名优化教程
  • 设计公司网站详情网站推广优化是什么意思
  • wordpress 一键生成山东seo
  • 网站错误代码 处理数字营销平台有哪些
  • 织梦网站模板安装教程靠谱的代写平台
  • 时尚类网站设计公司网络安全培训
  • 大黄网站.巨量算数官方入口
  • 学风网站建设西地那非片说明书
  • 深圳专业优定软件网站建设企业网站设计
  • 如何做视频网站技术网络营销方式包括哪些
  • 郑州动力无限网站建设创建网站免费注册
  • 网页版html编辑器网站功能优化
  • 物流网站怎么做推广东莞网站建设推广
  • 网站后台维护怎么做站长之家域名解析
  • 充电宝网站建设策划书百度知道首页
  • 苏州做学校网站的站长工具ip地址查询
  • 天津做网站制作公司seo推广什么意思
  • 网上做打字任务的网站百度反馈中心
  • 上海本地网站建设优化神马排名软件
  • 怎么把做的网站传小程序搭建教程
  • vs做网站头部的代码谷歌推广费用多少