国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

網(wǎng)絡(luò)營(yíng)銷案例分析200字關(guān)鍵詞seo如何優(yōu)化

網(wǎng)絡(luò)營(yíng)銷案例分析200字,關(guān)鍵詞seo如何優(yōu)化,搭建網(wǎng)站案例精粹,做營(yíng)銷看的網(wǎng)站有哪些如何實(shí)現(xiàn) Es 全文檢索、高亮文本略縮處理 前言技術(shù)選型JAVA 常用語法說明全文檢索開發(fā)高亮開發(fā)Es Map 轉(zhuǎn)對(duì)象使用核心代碼 Trans 接口(支持父類屬性的復(fù)雜映射)Trans 接口的不足真實(shí)項(xiàng)目落地效果 前言 最近手上在做 Es 全文檢索的需求,類似于…

如何實(shí)現(xiàn) Es 全文檢索、高亮文本略縮處理

    • 前言
    • 技術(shù)選型
    • JAVA 常用語法說明
    • 全文檢索開發(fā)
    • 高亮開發(fā)
    • Es Map 轉(zhuǎn)對(duì)象使用
    • 核心代碼 Trans 接口(支持父類屬性的復(fù)雜映射)
    • Trans 接口的不足
    • 真實(shí)項(xiàng)目落地效果

前言

最近手上在做 Es 全文檢索的需求,類似于百度那種,根據(jù)關(guān)鍵字檢索出對(duì)應(yīng)的文章,然后高亮顯示,特此記錄一下,其實(shí)主要就是處理 Es 數(shù)據(jù)那塊復(fù)雜,涉及到高亮文本替換以及高亮字段截取,還有要考慮到代碼的復(fù)用性,是否可以將轉(zhuǎn)換代碼抽離出來,提供給不同結(jié)構(gòu)的索引來使用。

技術(shù)選型

像市面上有的 Spring Data,碼云上面的 GVP 項(xiàng)目 (EasyEs)等其他封裝框架。使用起來確實(shí)很方便,但是考慮到由于開源項(xiàng)目的不穩(wěn)定性且 Es 不同版本間語法差異比較大,決定使用原生的 Api。也就是使用 RestHighLevelClient。

JAVA 常用語法說明

查時(shí)間范圍內(nèi)的數(shù)據(jù) BoolQuery 里面嵌套一個(gè) RangeQuery 即可在RangeQuery 里面指定時(shí)間范圍。BoolQuery.must() 各位理解為 Mybatis 中的 eq 方法即可,必須包含的意思。

   RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery(articleRequest.getSortType());if (StringUtils.isNotEmpty(articleRequest.getBeginTime())) {rangeQuery.gte(articleRequest.getBeginTime());}if (StringUtils.isNotEmpty(articleRequest.getEndTime())) {rangeQuery.lte(articleRequest.getEndTime());}boolQuery.must(rangeQuery);

BoolQuery.should() 方法可以理解為 OR 可包含可不包含,多字段全文檢索時(shí)應(yīng)用 shoud。

BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
boolQuery.should(QueryBuilders.matchPhraseQuery(articleRequest.getKeys()[i], articleRequest.getKeyword()));

termsQuery 字符精確匹配

QueryBuilders.termsQuery()

字符短句匹配,字符不會(huì)進(jìn)行分詞

QueryBuilders.matchPhraseQuery()

分詞匹配

QueryBuilders.multiMatchQuery()

全文檢索開發(fā)

核心代碼如下

    BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();if (StringUtils.isNotEmpty(articleRequest.getKeyword())) {for (int i = 0; i < articleRequest.getKeys().length; i++) {//根據(jù)短句匹配boolQuery.should(QueryBuilders.matchPhraseQuery(articleRequest.getKeys()[i], articleRequest.getKeyword()));}}

高亮開發(fā)

里面可以指定高亮的字段,以及高亮前綴,尾綴,API的調(diào)用,直接 copy 就行

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().highlighter(new HighlightBuilder().requireFieldMatch(false).field("author").field("title").field("body").field("attachments.filename").preTags(EsConstant.HIGHT_PREFIX).postTags(EsConstant.HIGHT_END).fragmentSize(800000)//下面這兩項(xiàng),如果你要高亮如文字內(nèi)容等有很多字的字段,必須配置,不然會(huì)導(dǎo)致高亮不全,文章內(nèi)容缺失等;.numOfFragments(0)).query(boolQuery).from(articleRequest.getPage() - 1).size(articleRequest.getSize())

Es Map 轉(zhuǎn)對(duì)象使用

由于索引結(jié)構(gòu)是已 ArticleResponse 格式存儲(chǔ)的,查詢的時(shí)候也需將的得到 SourceAsMap 轉(zhuǎn)換成 ArticleResponse 格式,核心邏輯我都封裝到 Trans 接口了。利用反射實(shí)現(xiàn)的,當(dāng)然也可以用其他技術(shù)實(shí)現(xiàn),例如 MapStruct 在編譯期間就自動(dòng)生成對(duì)應(yīng)的 get、set 方法,比反射效率高點(diǎn),畢竟反射是運(yùn)行期間的屬性映射!!!!

 SearchHits hits = restHighLevelClient.search(new SearchRequest().indices(indexname).source(searchSourceBuilder)).getHits();for (SearchHit hit : hits) {result.add(new ArticleResponse().trans(hit.getSourceAsMap(),hit.getHighlightFields(),Collections.singletonList("attachments.filename")));

使用的話只需讓 ArticleResponse 類實(shí)現(xiàn) Trans 接口,即可調(diào)用里面的 trans 方法。
在這里插入圖片描述

核心代碼 Trans 接口(支持父類屬性的復(fù)雜映射)

主要邏輯就是挨個(gè)拿到本身、然后遞歸獲取父類的所有字段名稱、字段類型放到一個(gè) Map(nameTypeMap) 中,然后遍歷 SourceAsMap 挨個(gè)進(jìn)行字段類型匹配校驗(yàn),如果是 String 類型直接進(jìn)行反射填充屬性。
在這里插入圖片描述
非 String 類型,進(jìn)行類型轉(zhuǎn)換然后再進(jìn)行屬性填充。
在這里插入圖片描述
以及高亮字段文本略縮的處理,主要就是用了下 Jsoup 中去除 Html 標(biāo)簽的 Api,本來想著讓前端自己去找插件看能不能處理下的,無奈說處理不了,想了個(gè)取巧的方法,高亮標(biāo)簽我用特殊字符,然后去除所有的 html 標(biāo)簽后,我的特殊字符還存在,之后將特殊字符再次替換回高亮 Html 標(biāo)簽,這樣就得到了只存在我自定義高亮 Html 標(biāo)簽的一段文本了,同時(shí)高亮標(biāo)簽里面我塞了一個(gè) id,之后根據(jù)高亮標(biāo)簽中的 id 截取字符即可,即可實(shí)現(xiàn)文本略縮的效果,同事直呼秒啊哈哈哈哈

在這里插入圖片描述
在這里插入圖片描述

/*** map 轉(zhuǎn)對(duì)象* author:zzh*/
public interface Trans<T> {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Class getTargetClass();/*** 邏輯寫的太多了,可以搞幾個(gè)抽象類抽分功能* @param SourceAsMap           原始數(shù)據(jù)* @param highlightFieldsSource 高亮數(shù)據(jù)* @param highLightFields       高亮字段*/default Object trans(Map<String, Object> SourceAsMap, Map<String, HighlightField> highlightFieldsSource, List<String> highLightFields) throws IntrospectionException, InstantiationException, IllegalAccessException {Object o = getTargetClass().newInstance();Class tclass = getTargetClass();HashMap<String, Class> nameTypeMap = new HashMap<>();//找到父類的所有字段do {Arrays.stream(tclass.getDeclaredFields()).forEach(field -> {field.setAccessible(true);//key:字段名稱,value:字段類型nameTypeMap.put(field.getName(), field.getType());});tclass = tclass.getSuperclass();} while (!tclass.equals(Object.class));PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(o.getClass()).getPropertyDescriptors();Arrays.stream(propertyDescriptors).forEach(propertyDescriptor -> {if (!"targetClass".equals(propertyDescriptor.getName()) && !Objects.isNull(SourceAsMap.get(propertyDescriptor.getName()))) {try {Method writeMethod = propertyDescriptor.getWriteMethod();if (null != writeMethod) {if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {writeMethod.setAccessible(true);}Object sourceValue = SourceAsMap.get(propertyDescriptor.getName());//父類以及自己所有字段類型Class aClass = nameTypeMap.get(propertyDescriptor.getName());//String 類型以及高亮直接賦值if (sourceValue.getClass().equals(aClass)) {HighlightField highlightObject = highlightFieldsSource.get(propertyDescriptor.getName());//如果高亮字段是 body,為了避免高亮文本處于文章末尾搜索頁顯示不到的問題,因此采用截取字符串將高亮字段偏移至前面if ("body".equals(propertyDescriptor.getName()) && null != highlightObject) {String highlightString = highlightObject.getFragments()[0].toString();//去除所有 html 標(biāo)簽,并將自定義高亮前綴替換 span 標(biāo)簽,這樣就實(shí)現(xiàn)了只保留高亮標(biāo)簽的目的了highlightString = Jsoup.parse(highlightString).body().text().replaceAll(EsConstant.HIGHT_PREFIX, EsConstant.HIGHT_PREFIX_HTML).replaceAll(EsConstant.HIGHT_END, EsConstant.HIGHT_END_HTML);//高亮字段前 50 個(gè)字到文章末尾highlightString = highlightString.substring((highlightString.indexOf(EsConstant.HIGHT_HTML_ID) - EsConstant.HIGHT_SIZE) < 0? 0 : (highlightString.indexOf(EsConstant.HIGHT_HTML_ID) -  EsConstant.HIGHT_SIZE));writeMethod.invoke(o, highlightObject != null ? highlightString : SourceAsMap.get(propertyDescriptor.getName()));} else {//非 body 的其他高亮字段正常替換高亮文本writeMethod.invoke(o, highlightObject != null ? highlightObject.getFragments()[0].toString().replaceAll(EsConstant.HIGHT_PREFIX, EsConstant.HIGHT_PREFIX_HTML).replaceAll(EsConstant.HIGHT_END, EsConstant.HIGHT_END_HTML) : SourceAsMap.get(propertyDescriptor.getName()));}}/*** 類型不一致強(qiáng)轉(zhuǎn),這里可以搞個(gè)策略模式優(yōu)化優(yōu)化*/else {if (aClass.equals(Date.class)) {Date parse = simpleDateFormat.parse(String.valueOf(SourceAsMap.get(propertyDescriptor.getName())));writeMethod.invoke(o, parse);}if (aClass.equals(Integer.class)) {writeMethod.invoke(o, Integer.valueOf(String.valueOf(SourceAsMap.get(propertyDescriptor.getName()))));}if (aClass.equals(Long.class)) {writeMethod.invoke(o, Long.valueOf(String.valueOf(SourceAsMap.get(propertyDescriptor.getName()))));}if (aClass.equals(List.class)) {ArrayList<Map<String, Object>> oraginSources = (ArrayList<Map<String, Object>>) SourceAsMap.get(propertyDescriptor.getName());//復(fù)雜對(duì)象高亮字段映射if (null != oraginSources && 0 != highlightFieldsSource.size()) {for (int i = 0; i < oraginSources.size(); i++) {for (int j = 0; j < highLightFields.size(); j++) {try {if (highlightFieldsSource.containsKey(highLightFields.get(j))) {oraginSources.get(i).put(highLightFields.get(j).split("\\.")[1],highlightFieldsSource.get(highLightFields.get(j)).getFragments()[j].toString().replaceAll(EsConstant.HIGHT_PREFIX, EsConstant.HIGHT_PREFIX_HTML).replaceAll(EsConstant.HIGHT_END, EsConstant.HIGHT_END_HTML));}} catch (Exception e) {e.printStackTrace();}}}}writeMethod.invoke(o, oraginSources);}if (aClass.equals(int.class)) {writeMethod.invoke(o, Integer.parseInt(String.valueOf(SourceAsMap.get(propertyDescriptor.getName()))));}}} else throw new RuntimeException(propertyDescriptor.getName() + "~ writeMethod is null!!!!!");} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}});return o;}}

Trans 接口的不足

追求極至代碼解耦的人,里面的類型轉(zhuǎn)換的代碼可以搞個(gè)策略模式優(yōu)化優(yōu)化。Trans 接口定義一個(gè)就好,可以搞幾個(gè)抽象類,譬如專門處理高亮文本的抽象類、不涉及到嵌套對(duì)象的抽象類轉(zhuǎn)換、以及通用轉(zhuǎn)換抽象類出來,寫多了感覺自己再寫源碼了,那些搞開源項(xiàng)目的還有一些主流框架的源碼不都是這么干的,但是需要花費(fèi)一定的精力去寫,筆者比較懶,下完班只想回家美美的打打游戲,追追劇,就點(diǎn)到為止了。

真實(shí)項(xiàng)目落地效果

在這里插入圖片描述
復(fù)雜對(duì)象高亮字段替換效果在這里插入圖片描述

http://aloenet.com.cn/news/34482.html

相關(guān)文章:

  • 網(wǎng)站整體運(yùn)營(yíng)思路互聯(lián)網(wǎng)推廣引流
  • 中國(guó)招標(biāo)投標(biāo)網(wǎng)查詢平臺(tái)站長(zhǎng)之家 seo查詢
  • 網(wǎng)站輪播廣告代碼怎樣搭建一個(gè)網(wǎng)站
  • 無錫 網(wǎng)站建設(shè)公司廣州做seo整站優(yōu)化公司
  • 榆林市網(wǎng)站建設(shè)網(wǎng)站開發(fā)工具
  • 深圳專業(yè)網(wǎng)站制作費(fèi)用怎么建一個(gè)自己的網(wǎng)站
  • 政務(wù)公開政府網(wǎng)站建設(shè)管理百度刷搜索詞
  • wordpress 首頁調(diào)用頁面標(biāo)題城關(guān)網(wǎng)站seo
  • 廣州 網(wǎng)站建設(shè)網(wǎng)絡(luò)推廣網(wǎng)頁設(shè)計(jì)免費(fèi)推廣廣告鏈接
  • 學(xué)校網(wǎng)站推廣seo關(guān)鍵詞排名優(yōu)化怎樣
  • 國(guó)外炫酷網(wǎng)站外貿(mào)平臺(tái)app
  • 網(wǎng)業(yè)端云服務(wù)武漢seo網(wǎng)站排名優(yōu)化
  • 減肥網(wǎng)站源碼seo需求
  • 國(guó)內(nèi)最好的crm軟件南昌seo技術(shù)外包
  • 個(gè)人備案網(wǎng)站做企業(yè)網(wǎng)可以嗎北京搜索引擎優(yōu)化主管
  • 網(wǎng)站專題建設(shè)合同2024新聞熱點(diǎn)事件
  • wordpress布置網(wǎng)站教程友情鏈接只有鏈接
  • seo搜索引擎優(yōu)化技術(shù)教程關(guān)鍵詞排名優(yōu)化提升培訓(xùn)
  • 網(wǎng)站信息資料庫(kù)建設(shè)品牌seo是什么
  • 什么專業(yè)的會(huì)做網(wǎng)站網(wǎng)站統(tǒng)計(jì)
  • 建設(shè)銀行網(wǎng)站電腦上不去網(wǎng)絡(luò)營(yíng)銷策劃書2000字
  • 煩惱可以做網(wǎng)站嗎搜索熱度查詢
  • 家教網(wǎng)站建設(shè)的推廣免費(fèi)網(wǎng)站流量
  • 倒計(jì)時(shí)網(wǎng)站模板搜索引擎關(guān)鍵詞seo優(yōu)化公司
  • 上海網(wǎng)站建設(shè)設(shè)計(jì)制作寧波seo排名方案優(yōu)化公司
  • 國(guó)內(nèi)出名的設(shè)計(jì)網(wǎng)站有哪些免費(fèi)網(wǎng)站制作軟件平臺(tái)
  • 好姑娘中文在線觀看國(guó)語高清免費(fèi)深圳白帽優(yōu)化
  • 廈門網(wǎng)站建設(shè)哪家好百度一級(jí)代理商
  • 房地產(chǎn)網(wǎng)站大全東莞日增感染人數(shù)超25萬
  • 青島專業(yè)網(wǎng)站制作團(tuán)隊(duì)肇慶百度快照優(yōu)化