ES实战 | 黑马旅游案例

这篇具有很好参考价值的文章主要介绍了ES实战 | 黑马旅游案例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

关键词搜索

ES实战 | 黑马旅游案例

需求:根据文字搜索,也可以选择标签搜索

思路:用bool查询,先根据关键词查询全部,再根据标签过滤。

public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
    @Autowired
    private RestHighLevelClient client;
    @Override
    public PageResult search(RequestParams params) throws IOException {
        SearchRequest request = new SearchRequest("hotel");
//        关键字搜索
        QueryBuilder query = buildBasicQuery(params);
        request.source().query(query);
        
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        return extracted(response);
    }

    private static QueryBuilder buildBasicQuery(RequestParams params) {
        String key  = params.getKey();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//        query
//        关键字搜索
        if ("".equals(key) || key==null){
            boolQuery.must(QueryBuilders.matchAllQuery());
        }else {
            boolQuery.must(QueryBuilders.matchQuery("all",key));
        }
//        过滤条件
        if (params.getMinPrice()!=null && params.getMaxPrice()!=null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(params.getMinPrice()).lte(params.getMaxPrice()));
        }
        if (!("".equals(params.getCity()) || params.getCity()==null)){
            boolQuery.filter(QueryBuilders.termQuery("city", params.getCity()));
        }
        if (!("".equals(params.getBrand()) || params.getBrand()==null)){
            boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand()));
        }
        if (!("".equals(params.getStarName()) || params.getStarName()==null)){
            boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName()));
        }
        return boolQuery;
    }

    private static PageResult extracted(SearchResponse response) {
        SearchHits searchHits = response.getHits();
        long total = searchHits.getTotalHits().value;
        SearchHit[] hits = searchHits.getHits();
        List<HotelDoc> list = Arrays.stream(hits).map(item -> {
            String jsonStr = item.getSourceAsString();
            Object[] sortValues = item.getSortValues();
            HotelDoc hotelDoc = JSONObject.parseObject(jsonStr, HotelDoc.class);
            return hotelDoc;
        }).collect(Collectors.toList());
        return new PageResult(total, list);
    }
}

分页排序

ES实战 | 黑马旅游案例

需求:实现分页排序

思路:分页跟排序是单独的功能,可以根据选项排好序再分页

@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
    @Autowired
    private RestHighLevelClient client;
    private static Boolean isLocation = false;
    @Override
    public PageResult search(RequestParams params) throws IOException {
        SearchRequest request = new SearchRequest("hotel");
//        关键字搜索
        QueryBuilder query = buildBasicQuery(params);
        request.source().query(query);
//        分页
        int page = params.getPage();
        int size = params.getSize();
        request.source().from((page-1)*size).size(size);
//        排序
        if (!("default".equals(params.getSortBy()))){
            FieldSortBuilder sortBy = SortBuilders.fieldSort(params.getSortBy());
            if ("price".equals(params.getSortBy())){
                sortBy.order(SortOrder.ASC);
            }else {
                sortBy.order(SortOrder.DESC);
            }
            request.source().sort(sortBy);
        }
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        return extracted(response);
    }

    private static QueryBuilder buildBasicQuery(RequestParams params) {
        String key  = params.getKey();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//        query
//        关键字搜索
        if ("".equals(key) || key==null){
            boolQuery.must(QueryBuilders.matchAllQuery());
        }else {
            boolQuery.must(QueryBuilders.matchQuery("all",key));
        }
//        过滤条件
        if (params.getMinPrice()!=null && params.getMaxPrice()!=null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(params.getMinPrice()).lte(params.getMaxPrice()));
        }
        if (!("".equals(params.getCity()) || params.getCity()==null)){
            boolQuery.filter(QueryBuilders.termQuery("city", params.getCity()));
        }
        if (!("".equals(params.getBrand()) || params.getBrand()==null)){
            boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand()));
        }
        if (!("".equals(params.getStarName()) || params.getStarName()==null)){
            boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName()));
        }
		return boolQuery;
    }

    private static PageResult extracted(SearchResponse response) {
        SearchHits searchHits = response.getHits();
        long total = searchHits.getTotalHits().value;
        SearchHit[] hits = searchHits.getHits();
        List<HotelDoc> list = Arrays.stream(hits).map(item -> {
            String jsonStr = item.getSourceAsString();
            Object[] sortValues = item.getSortValues();
            HotelDoc hotelDoc = JSONObject.parseObject(jsonStr, HotelDoc.class);
            return hotelDoc;
        }).collect(Collectors.toList());
        return new PageResult(total, list);
    }
}

距离显示

ES实战 | 黑马旅游案例

要求:点击获取位置后,根据距离显示酒店,且要显示距离

思路:先判断有没有点击地图,如果携带了位置的请求就代表点击了地图,就需要根据坐标查询,且规定坐标先查找,可以保证在sort里value[0]就是坐标值

ES实战 | 黑马旅游案例

@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
    @Autowired
    private RestHighLevelClient client;
    private static Boolean isLocation = false;
    @Override
    public PageResult search(RequestParams params) throws IOException {
        SearchRequest request = new SearchRequest("hotel");
//        关键字搜索
        QueryBuilder query = buildBasicQuery(params);
        request.source().query(query);
//        分页
        int page = params.getPage();
        int size = params.getSize();
        request.source().from((page-1)*size).size(size);
//        排序
        String location = params.getLocation();
//        坐标排序
        if (!("".equals(location) || location==null)){
            GeoDistanceSortBuilder locationSort = SortBuilders.geoDistanceSort("location",new GeoPoint(location)).order(SortOrder.ASC).unit(DistanceUnit.KILOMETERS);
            request.source().sort(locationSort);
            FieldSortBuilder priceSort = SortBuilders.fieldSort("price").order(SortOrder.ASC);
            request.source().sort(priceSort);
            isLocation =true;
        }
//		  price/defult/socre排序        
        if (!("default".equals(params.getSortBy()))){
            FieldSortBuilder sortBy = SortBuilders.fieldSort(params.getSortBy());
            if ("price".equals(params.getSortBy())){
                sortBy.order(SortOrder.ASC);
            }else {
                sortBy.order(SortOrder.DESC);
            }
            request.source().sort(sortBy);
        }
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        return extracted(response);
    }

    private static QueryBuilder buildBasicQuery(RequestParams params) {
        String key  = params.getKey();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//        query
//        关键字搜索
        if ("".equals(key) || key==null){
            boolQuery.must(QueryBuilders.matchAllQuery());
        }else {
            boolQuery.must(QueryBuilders.matchQuery("all",key));
        }
//        过滤条件
        if (params.getMinPrice()!=null && params.getMaxPrice()!=null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(params.getMinPrice()).lte(params.getMaxPrice()));
        }
        if (!("".equals(params.getCity()) || params.getCity()==null)){
            boolQuery.filter(QueryBuilders.termQuery("city", params.getCity()));
        }
        if (!("".equals(params.getBrand()) || params.getBrand()==null)){
            boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand()));
        }
        if (!("".equals(params.getStarName()) || params.getStarName()==null)){
            boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName()));
        }
		return boolQuery;
    }

    private static PageResult extracted(SearchResponse response) {
        SearchHits searchHits = response.getHits();
        long total = searchHits.getTotalHits().value;
        SearchHit[] hits = searchHits.getHits();
        List<HotelDoc> list = Arrays.stream(hits).map(item -> {
            String jsonStr = item.getSourceAsString();
            Object[] sortValues = item.getSortValues();
            HotelDoc hotelDoc = JSONObject.parseObject(jsonStr, HotelDoc.class);
            if (sortValues.length>0 && isLocation){
                Object sortValue = sortValues[0];
                hotelDoc.setDistance(sortValue);
            }
            return hotelDoc;
        }).collect(Collectors.toList());
        return new PageResult(total, list);
    }
}

广告置顶

ES实战 | 黑马旅游案例

要求:广告置顶,有些广告需要在展示搜索结果的时候排在前面

思路:利用functionScore来做,但是functionScore是用不到bool的只能用普通的查询,在文档中维护一个字段叫isAD,在functions中过滤出isAD的文档,重新分配权重

@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
    @Autowired
    private RestHighLevelClient client;
    private static Boolean isLocation = false;
    @Override
    public PageResult search(RequestParams params) throws IOException {
        SearchRequest request = new SearchRequest("hotel");
//        关键字搜索
        QueryBuilder query = buildBasicQuery(params);
        request.source().query(query);
//        分页
        int page = params.getPage();
        int size = params.getSize();
        request.source().from((page-1)*size).size(size);
//        排序
        String location = params.getLocation();
        if (!("".equals(location) || location==null)){
            GeoDistanceSortBuilder locationSort = SortBuilders.geoDistanceSort("location",new GeoPoint(location)).order(SortOrder.ASC).unit(DistanceUnit.KILOMETERS);
            request.source().sort(locationSort);
            FieldSortBuilder priceSort = SortBuilders.fieldSort("price").order(SortOrder.ASC);
            request.source().sort(priceSort);
            isLocation =true;
        }
        if (!("default".equals(params.getSortBy()))){
            FieldSortBuilder sortBy = SortBuilders.fieldSort(params.getSortBy());
            if ("price".equals(params.getSortBy())){
                sortBy.order(SortOrder.ASC);
            }else {
                sortBy.order(SortOrder.DESC);
            }
            request.source().sort(sortBy);
        }
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        return extracted(response);
    }

    private static QueryBuilder buildBasicQuery(RequestParams params) {
        String key  = params.getKey();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//        query
//        关键字搜索
        if ("".equals(key) || key==null){
            boolQuery.must(QueryBuilders.matchAllQuery());
        }else {
            boolQuery.must(QueryBuilders.matchQuery("all",key));
        }
//        过滤条件
        if (params.getMinPrice()!=null && params.getMaxPrice()!=null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(params.getMinPrice()).lte(params.getMaxPrice()));
        }
        if (!("".equals(params.getCity()) || params.getCity()==null)){
            boolQuery.filter(QueryBuilders.termQuery("city", params.getCity()));
        }
        if (!("".equals(params.getBrand()) || params.getBrand()==null)){
            boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand()));
        }
        if (!("".equals(params.getStarName()) || params.getStarName()==null)){
            boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName()));
        }

//        广告置顶
        return QueryBuilders.functionScoreQuery(boolQuery, new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                        QueryBuilders.termQuery("isAD",true),
                        ScoreFunctionBuilders.weightFactorFunction(10)
                )
        }).boostMode(CombineFunction.MULTIPLY);
    }

    private static PageResult extracted(SearchResponse response) {
        SearchHits searchHits = response.getHits();
        long total = searchHits.getTotalHits().value;
        SearchHit[] hits = searchHits.getHits();
        List<HotelDoc> list = Arrays.stream(hits).map(item -> {
            String jsonStr = item.getSourceAsString();
            Object[] sortValues = item.getSortValues();
            HotelDoc hotelDoc = JSONObject.parseObject(jsonStr, HotelDoc.class);
            if (sortValues.length>0 && isLocation){
                Object sortValue = sortValues[0];
                hotelDoc.setDistance(sortValue);
            }
            return hotelDoc;
        }).collect(Collectors.toList());
        return new PageResult(total, list);
    }
}

标签聚合

ES实战 | 黑马旅游案例

需求:从后台文档中获取实际数据,传入前端页面显示,且会动态变化,比如:选择了上海,就展示在上海的品牌,而不在上海的品牌就不显示

思路:先根据用户条件搜索文档,按照类别聚合

    @Override
    public Map<String, List<String>> filters(RequestParams requestParams){
        Map<String, List<String>> listMap = null;
        try {
            SearchRequest request = new SearchRequest("hotel");
//        查询条件构建
            searchAggs(request,requestParams);
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            Aggregations aggregations = response.getAggregations();
            listMap = new HashMap<>();
            listMap.put("city",getList(aggregations, "getCity"));
            listMap.put("brand",getList(aggregations, "getBrand"));
            listMap.put("starName",getList(aggregations, "getStarName"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return listMap;
    }

    private void searchAggs(SearchRequest request,RequestParams requestParams) {
        QueryBuilder queryBuilder = buildBasicQuery(requestParams);
        request.source().query(queryBuilder);
//        查询品牌
        request.source().aggregation(
                AggregationBuilders
                        .terms("getBrand")
                        .field("brand")
                        .size(20));
//        查询城市
        request.source().aggregation(
                AggregationBuilders
                        .terms("getCity")
                        .field("city")
                        .size(20));
//        查询星级
        request.source().aggregation(
                AggregationBuilders
                        .terms("getStarName")
                        .field("starName")
                        .size(20));
    }

    private List<String> getList(Aggregations aggregations, String name) {
        Terms getBrand = aggregations.get(name);
        List<String> list = new ArrayList<>();
        for (Terms.Bucket bucket : getBrand.getBuckets()) {
            String key = bucket.getKeyAsString();
            list.add(key);
        }
        return list;
    }

    private QueryBuilder buildBasicQuery(RequestParams params) {
        String key  = params.getKey();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//        query
//        关键字搜索
        if ("".equals(key) || key==null){
            boolQuery.must(QueryBuilders.matchAllQuery());
        }else {
            boolQuery.must(QueryBuilders.matchQuery("all",key));
        }
//        过滤条件
        if (params.getMinPrice()!=null && params.getMaxPrice()!=null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(params.getMinPrice()).lte(params.getMaxPrice()));
        }
        if (!("".equals(params.getCity()) || params.getCity()==null)){
            boolQuery.filter(QueryBuilders.termQuery("city", params.getCity()));
        }
        if (!("".equals(params.getBrand()) || params.getBrand()==null)){
            boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand()));
        }
        if (!("".equals(params.getStarName()) || params.getStarName()==null)){
            boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName()));
        }

//        广告置顶
        return QueryBuilders.functionScoreQuery(boolQuery, new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                        QueryBuilders.termQuery("isAD",true),
                        ScoreFunctionBuilders.weightFactorFunction(10)
                )
        }).boostMode(CombineFunction.MULTIPLY);
    }

自动补全

ES实战 | 黑马旅游案例

需求:要求用户输入拼音,可以根据输入的拼音自动补全,例如:输入s自动补全 三,四,蛇

思路:利用分词器,在新增文档的时候,根据拼音分词器把品牌,地址做拆分,用户输入受字母的时候,后台根据首字符检索字段的拼音,要设计好拼音分词器的拆分条件

/**
 * 自动补全
 * @param key 补全前缀
 * @return 补全数组
 */
@Override
public List<String> suggestion(String key) {
    List<String> collect;
    try {
        SearchRequest request = new SearchRequest("hotel");
        request.source().suggest(new SuggestBuilder()
                .addSuggestion("mySuggestion",
                        SuggestBuilders
                                .completionSuggestion("suggestion")
                                .prefix(key)
                                .skipDuplicates(true)
                                .size(10)));
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        CompletionSuggestion mySuggestion = response.getSuggest().getSuggestion("mySuggestion");
        List<CompletionSuggestion.Entry.Option> options = mySuggestion.getOptions();
        collect = options.stream().map(item -> item.getText().string()).collect(Collectors.toList());
        System.err.println(collect);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    return collect;
}

构建索引库比较关键,这里把用不到的字段省略了,不然太冗余了

#hotel
PUT /hotel
{
  "mappings":{
    "properties":{
      "address":{
        "type": "keyword",
        "copy_to": "all"
      },
      "brand":{
        "type": "keyword",
        "copy_to": "all"
      },    
      "city":{
        "type": "keyword",
        "copy_to": "all"
      },
      "name":{
        "type": "text",
        "analyzer": "text_analyzere",
        "search_analyzer": "ik_smart",
        "copy_to": "all"
      },
      # all字段,用户确认搜索的时候用到的。analyzer代表新增文档的时候,按照text_analyzere这个分词器,根据最大粒度拆分,且用到了py拼音分词器。
      # search_analyzer,用户确认搜索的时候用这个分词器去拆分用户的输入信息
      "all":{
        "type": "text",
        "analyzer": "text_analyzere",
        "search_analyzer": "ik_max_word"
      },
      #suggestion专门为自动补全做的字段,类型只能是completion,completion是一个数组,数组内的字段只能是keyword不能拆分,因为如果拆分的话就有很多个值出来,keyword保证不可拆分,那么在同一个文档内这个suggestion是固定的,比如completion由品牌跟地址组成,品牌=如家,地址=北京,那这个分词器拆出来只能是:rujia/rj,beijing/bj,
      "suggestion":{
        "type": "completion",
        "analyzer": "completion_analyzere"
      }
    }
  },
  "settings": {
    "analysis": {
      "analyzer": {
      #text的分词器,新增文档的时候有些text字段可能搜索的时候需要用到。
        "text_analyzere":{
          "tokenizer":"ik_max_word",
          "filter":"py"
        },
      #completion的分词器
        "completion_analyzere":{
          "tokenizer":"keyword",
          "filter":"py"
        }
      },
      "filter": {
          "type": "pinyin", //类型
          "keep_full_pinyin": false,//当启用这个选项,如: 刘德华 >[ liu , de , hua ),默认值:真的
          "keep_joined_full_pinyin": true,//当启用此选项时,例如: 刘德华 >[ liudehua ],默认:false
          "keep_original": true,//当启用此选项时,将保留原始输入,默认值:false
          "limit_first_letter_length": 16,//set first_letter结果的最大长度,默认值:16
          "remove_duplicated_term": true,//当此选项启用时,重复项将被删除以保存索引,例如: de的 > de ,默认:false,注:职位相关查询可能会受到影响
          "none_chinese_pinyin_tokenize" :false //非中国字母分解成单独的拼音词如果拼音,默认值:true,如:liu , de , hua , a , li , ba , ba , 13 , zhuang , han ,注意: keep_none_chinese 和 keep_none_chinese_together 应该启用
      }
    }
  }
}

数据同步

利用mq实现数据同步

生产者

@PostMapping
public void saveHotel(@RequestBody Hotel hotel){
    Long i = 1L;
    hotel.setId(i);
    hotelService.save(hotel);
    String exchangeName = "topic.hotel";
    String key = "hotel.insert";
    rabbitTemplate.convertAndSend(exchangeName,key,hotel.getId());
    System.err.println("发送成功--->新增");
}

消费者文章来源地址https://www.toymoban.com/news/detail-408471.html

@Bean
public Queue queueInsert(){
    return new Queue("topic.insert.queue",true);
}
@Bean
public TopicExchange topicExchange(){
    return new TopicExchange("topic.hotel");
}
@Bean
public Queue queueDelete(){
    return new Queue("topic.delete.queue",true);
}
@Bean
public Binding bindingTopicBuilder(TopicExchange topicExchange,Queue queueInsert){
    return BindingBuilder.bind(queueInsert).to(topicExchange).with("hotel.insert");
}
@Bean
public Binding bindingTopicBuilder2(TopicExchange topicExchange,Queue queueDelete){
    return BindingBuilder.bind(queueDelete).to(topicExchange).with("hotel.delete");
}
@Component
public class ListenMq {
    @Autowired
    private IHotelService hotelService;
    @RabbitListener(queues = "topic.insert.queue")
    public void listenInsert(Long id){
        hotelService.updateById(id);
    }

    @RabbitListener(queues = "topic.delete.queue")
    public void listenDelete(Long id){
        hotelService.deleteById(id);
    }
}
@Override
public void updateById(Long id) {
    try {
        IndexRequest request = new IndexRequest("hotel").id(id.toString());
        Hotel hotel = this.getById(id);
        HotelDoc hotelDoc = new HotelDoc(hotel);
        String jsonString = JSON.toJSONString(hotelDoc);
        request.source(jsonString, XContentType.JSON);
        client.index(request, RequestOptions.DEFAULT);
        System.err.println("新增一条数据");
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

到了这里,关于ES实战 | 黑马旅游案例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Elasticsearch的关键词搜索

    返回给前端的实体类 es对应的实体类 前端传递的搜索参数实体类 controller层 service层接口 service实现类 Springboot启动类

    2023年04月08日
    浏览(52)
  • X书关键词协议搜索

    搜索接口中的其他java层加密,详细见: https://codeooo.blog.csdn.net/article/details/122986633

    2024年02月16日
    浏览(43)
  • VIM统计搜索关键词命令

    :%s/.//gn        统计字符数 :%s/i+//gn    统计单词数 :%s/^//n           统计行数 :%s/keyword//g      统计任何地方出现的 \\\"keyword\\\"   :%s/keyword//gn    统计任何地方出现的 \\\"keyword\\\" :%s/keyword/ :这部分是 Vim 的替换命令的开头。:%s 表示在整个文件范围内进行替换操作。keyword 是要查

    2024年02月09日
    浏览(64)
  • 网站优化搜索引擎与关键词

    网站优化搜索引擎与 人们不应该高估搜索引擎的智商。这不利于seo的研究,事实上,搜索引擎是非常愚蠢的,让我们举一个非常简单的例子,你在搜索引擎中输入“教师”这个词,搜索引擎就会给出一个准确的搜索列表。我们不会给出“教师”一词的检索信息,但我们

    2024年02月09日
    浏览(100)
  • Vue实现搜索关键词高亮显示

    最近写移动端项目的时候,遇到搜索高亮的需求,写篇文章纪录一下 先看效果:   以上为实现效果展示; 整体思路 : 对后台返回的数据进行操作,(我这里是模拟数据),使用正则去匹配搜索后,使用replace进行字符串的替换; 渲染数据部分使用v-html进行动态展示即可

    2024年02月15日
    浏览(51)
  • 抖音关键词搜索小程序排名怎么做

    抖音搜索小程序排名怎么做 1 分钟教你制作一个抖音小程序。 抖音小程序就是我的视频,左下方这个蓝色的链接,点进去就是抖音小程序。 如果你有了这个小程序,发布视频的时候可以挂载这个小程序,直播的时候也可以挂载这个小程序进行带货。   制作小程序一共

    2024年02月13日
    浏览(66)
  • highlight.js 实现搜索关键词高亮效果

    先看效果: 更新:增加切换显示 折腾了老半天,记录一下 注意事项都写注释了 代码: 更新后代码:

    2024年02月02日
    浏览(52)
  • Python获取高德POI(关键词搜索法)

    该篇文章是搜索法获取高德poi,但鉴于无法突破900条记录的上限,因此重写了 矩形搜索法 的文章,具体可参考以下文章: 高德poi获取之矩形搜索法(冲出900条限制) (建议没有python基础的朋友先阅读该篇再看矩形搜索法!) 首先我们需要明白一些常识 poi是兴趣点,它

    2024年02月06日
    浏览(58)
  • 【爬虫】根据关键词自动搜索并爬取结果

    根据自动搜索并爬取网页的信息 网页有两种情况:可以直接获取页数的和不可以直接获取页数的; 两种情况可以采取不同的方法: 情况一:先爬取页数,再爬取每页的数据 情况二:无法爬取到页码数,只能换页爬取的

    2024年02月12日
    浏览(46)
  • 搜索引擎都有哪些关键词匹配方式

     1. 完全匹配 这个应该是很多SEO最熟悉的一种匹配方式了,什么是完全匹配呢?比如说我的是“SEO培训”,如果网站中完整的出现了这个词,并且的位置也匹配,这样就是完全匹配。这里需要特别明确说的一点就是,完全匹配一定是一个单独的才是,什么是

    2024年02月13日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包