zoukankan      html  css  js  c++  java
  • ElasticSearch搜索实例含高亮显示及搜索的特殊字符过滤

    应用说明见代码注解。

    1.简单搜索实例展示:

    复制代码
        public void search() throws IOException {
            // 自定义集群结点名称
            String clusterName = "elasticsearch_pudongping";
    
            // 获取客户端
            Client client = ESClient.initClient(clusterName);
    
            // 创建查询索引,参数productindex表示要查询的索引库为productindex
            SearchRequestBuilder searchRequestBuilder = client
                    .prepareSearch("productindex");
    
            // 设置查询索引类型,setTypes("productType1", "productType2","productType3");
            // 用来设定在多个类型中搜索
            searchRequestBuilder.setTypes("productIndex");
    
            // 设置查询类型 1.SearchType.DFS_QUERY_THEN_FETCH = 精确查询 2.SearchType.SCAN =
            // 扫描查询,无序
            searchRequestBuilder.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);
    
            // 设置查询关键词
            searchRequestBuilder
                    .setQuery(QueryBuilders.fieldQuery("title", "Acer"));
    
            // 查询过滤器过滤价格在4000-5000内 这里范围为[4000,5000]区间闭包含,搜索结果包含价格为4000和价格为5000的数据
            searchRequestBuilder.setFilter(FilterBuilders.rangeFilter("price")
                    .from(4000).to(5000));
    
            // 分页应用
            searchRequestBuilder.setFrom(0).setSize(60);
    
            // 设置是否按查询匹配度排序
            searchRequestBuilder.setExplain(true);
    
            // 执行搜索,返回搜索响应信息
            SearchResponse response = searchRequestBuilder.execute().actionGet();
    
            SearchHits searchHits = response.getHits();
            SearchHit[] hits = searchHits.getHits();
            for (int i = 0; i < hits.length; i++) {
                SearchHit hit = hits[i];
                Map<String, Object> result = hit.getSource();
                // 打印map集合:{id=26, onSale=true, title=宏基Acer乐3, price=4009.0,
                // description=null, createDate=1380530123140, type=2}
                System.out.println(result);
            }
            System.out.println("search success ..");
    
        }
    复制代码

    说明:

    client.prepareSearch用来创建一个SearchRequestBuilder,搜索即由SearchRequestBuilder执行。

    client.prepareSearch方法有参数为一个或多个index,表现在数据库中,即零个或多个数据库名,你既可以使用(下面两个都可以表示在多个索引库中查找):

    client.prepareSearch().setIndices("index1","index2","index3","index4");

    或者:

    client.prepareSearch("index1","index2","index3","index4"); 


    SearchRequestBuilder常用方法说明:

    复制代码
    (1) setIndices(String... indices):上文中描述过,参数可为一个或多个字符串,表示要进行检索的index;
    
    (2) setTypes(String... types):参数可为一个或多个字符串,表示要进行检索的type,当参数为0个或者不调用此方法时,表示查询所有的type;
    
    setSearchType(SearchType searchType):执行检索的类别,值为org.elasticsearch.action.search.SearchType的元素,SearchType是一个枚举类型的类,
       其值如下所示:
       QUERY_THEN_FETCH:查询是针对所有的块执行的,但返回的是足够的信息,而不是文档内容(Document)。结果会被排序和分级,基于此,只有相关的块的文档对象会被返回。由于被取到的仅仅是这些,故而返回的hit的大小正好等于指定的size。这对于有许多块的index来说是很便利的(返回结果不会有重复的,因为块被分组了)
       QUERY_AND_FETCH:最原始(也可能是最快的)实现就是简单的在所有相关的shard上执行检索并返回结果。每个shard返回一定尺寸的结果。由于每个shard已经返回了一定尺寸的hit,这种类型实际上是返回多个shard的一定尺寸的结果给调用者。
       DFS_QUERY_THEN_FETCH:与QUERY_THEN_FETCH相同,预期一个初始的散射相伴用来为更准确的score计算分配了的term频率。
       DFS_QUERY_AND_FETCH:与QUERY_AND_FETCH相同,预期一个初始的散射相伴用来为更准确的score计算分配了的term频率。
       SCAN:在执行了没有进行任何排序的检索时执行浏览。此时将会自动的开始滚动结果集。
       COUNT:只计算结果的数量,也会执行facet。
    
    (4) setSearchType(String searchType),与setSearchType(SearchType searchType)类似,区别在于其值为字符串型的SearchType,值可为dfs_query_then_fetch、dfsQueryThenFetch、dfs_query_and_fetch、dfsQueryAndFetch、query_then_fetch、queryThenFetch、query_and_fetch或queryAndFetch;
    
    (5) setScroll(Scroll scroll)、setScroll(TimeValue keepAlive)和setScroll(String keepAlive),设置滚动,参数为Scroll时,直接用new Scroll(TimeValue)构造一个Scroll,为TimeValue或String时需要将TimeValue和String转化为Scroll;
    
    (6) setTimeout(TimeValue timeout)和setTimeout(String timeout),设置搜索的超时时间;
    
    (7) setQuery,设置查询使用的Query;
    
    (8) setFilter,设置过滤器;
    
    (9) setMinScore,设置Score的最小数量;
    
    (10) setFrom,从哪一个Score开始查;
    
    (11) setSize,需要查询出多少条结果;
    复制代码

    检索出结果后,通过response.getHits()可以得到所有的SearchHit,得到Hit后,便可迭代Hit取到对应的Document,转化成为需要的实体。

    2.搜索高亮显示

    spring-boot-starter-data-elasticsearch高亮显示场景的一个Demo


    org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder
    org.springframework.data.elasticsearch.core.SearchResultMapper
    org.springframework.data.domain.PageImpl
    org.elasticsearch.action.search.SearchResponse
    org.elasticsearch.search.SearchHit
    org.elasticsearch.search.highlight.HighlightField

            String preTag = "<font color='#dd4b39'>";//google的色值
            String postTag = "</font>";
            SearchQuery searchQuery = new NativeSearchQueryBuilder()
                    .withQuery(queryBuilder)
                    .withFilter(QueryBuilders.termQuery("status", CommConstants.ItemStatus.Normal))
                    .withSort(SortBuilders.fieldSort("modifiedTime").order(SortOrder.DESC))
                    .withPageable(pageable)
                    .withHighlightFields(new HighlightBuilder.Field("name").preTags(preTag).postTags(postTag)
                            , new HighlightBuilder.Field("memo").preTags(preTag).postTags(postTag))
                    .build();
    
            return elasticsearchTemplate.queryForPage(searchQuery, UserDocument.class, new SearchResultMapper() {
    
                @Override
                public <T> Page<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                    List<UserDocument> chunk = new ArrayList<>();
                    for (SearchHit searchHit : response.getHits()) {
                        if (response.getHits().getHits().length <= 0) {
                            return null;
                        }
                        UserDocument user = new UserDocument();
                        user.setId(Long.valueOf(searchHit.getId()));
                        //name or memoe
                        HighlightField name = searchHit.getHighlightFields().get("name");
                        if (name != null) {
                            user.setName(name.fragments()[0].toString());
                        }
                        HighlightField memo = searchHit.getHighlightFields().get("memo");
                        if (memo != null) {
                            user.setMemo(memo.fragments()[0].toString());
                        }
    
                        chunk.add(user);
                    }
                    if (chunk.size() > 0) {
                        return new PageImpl<T>((List<T>) chunk);
                    }
                    return null;
                }
            });

     

    @Test
    public void shouldReturnHighlightedFieldsForGivenQueryAndFields() {
    
        //given
        String documentId = randomNumeric(5);
        String actualMessage = "some test message";
        String highlightedMessage = "some <em>test</em> message";
    
        SampleEntity sampleEntity = SampleEntity.builder().id(documentId)
                .message(actualMessage)
                .version(System.currentTimeMillis()).build();
    
        IndexQuery indexQuery = getIndexQuery(sampleEntity);
    
        elasticsearchTemplate.index(indexQuery);
        elasticsearchTemplate.refresh(SampleEntity.class);
    
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(termQuery("message", "test"))
                .withHighlightFields(new HighlightBuilder.Field("message"))
                .build();
    
        Page<SampleEntity> sampleEntities = elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, new SearchResultMapper() {
            @Override
            public <T> Page<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                List<SampleEntity> chunk = new ArrayList<SampleEntity>();
                for (SearchHit searchHit : response.getHits()) {
                    if (response.getHits().getHits().length <= 0) {
                        return null;
                    }
                    SampleEntity user = new SampleEntity();
                    user.setId(searchHit.getId());
                    user.setMessage((String) searchHit.getSource().get("message"));
                    user.setHighlightedMessage(searchHit.getHighlightFields().get("message").fragments()[0].toString());
                    chunk.add(user);
                }
                if (chunk.size() > 0) {
                    return new PageImpl<T>((List<T>) chunk);
                }
                return null;
            }
        });
    
        assertThat(sampleEntities.getContent().get(0).getHighlightedMessage(), is(highlightedMessage));
    }

    http://stackoverflow.com/questions/37049764/how-to-provide-highlighting-with-spring-data-elasticsearch



    SearchRequestBuilder中的addHighlightedField()方法可以定制在哪个域值的检索结果的关键字上增加高亮

    复制代码
        public void search() throws IOException {
            // 自定义集群结点名称
            String clusterName = "elasticsearch_pudongping";
            
            // 获取客户端
            Client client = ESClient.initClient(clusterName);    
    
            // 创建查询索引,参数productindex表示要查询的索引库为productindex
            SearchRequestBuilder searchRequestBuilder = client
                    .prepareSearch("productindex");
    
            // 设置查询索引类型,setTypes("productType1", "productType2","productType3");
            // 用来设定在多个类型中搜索
            searchRequestBuilder.setTypes("productIndex");
    
            // 设置查询类型 1.SearchType.DFS_QUERY_THEN_FETCH = 精确查询 2.SearchType.SCAN = 扫描查询,无序
            searchRequestBuilder.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);
    
            // 设置查询关键词
            searchRequestBuilder
                    .setQuery(QueryBuilders.fieldQuery("title", "Acer"));
    
            // 查询过滤器过滤价格在4000-5000内 这里范围为[4000,5000]区间闭包含,搜索结果包含价格为4000和价格为5000的数据
            searchRequestBuilder.setFilter(FilterBuilders.rangeFilter("price")
                    .from(4000).to(5000));
    
            // 分页应用
            searchRequestBuilder.setFrom(0).setSize(60);
    
            // 设置是否按查询匹配度排序
            searchRequestBuilder.setExplain(true);
            
            //设置高亮显示
            searchRequestBuilder.addHighlightedField("title");
            searchRequestBuilder.setHighlighterPreTags("<span style="color:red">");
             searchRequestBuilder.setHighlighterPostTags("</span>");
            // 执行搜索,返回搜索响应信息
            SearchResponse response = searchRequestBuilder.execute().actionGet();
            
            //获取搜索的文档结果
            SearchHits searchHits = response.getHits();
            SearchHit[] hits = searchHits.getHits();
            ObjectMapper mapper = new ObjectMapper();
            for (int i = 0; i < hits.length; i++) {
                SearchHit hit = hits[i];
                //将文档中的每一个对象转换json串值
                String json = hit.getSourceAsString();
                //将json串值转换成对应的实体对象
                Product product = mapper.readValue(json, Product.class);  
                
                //获取对应的高亮域
                Map<String, HighlightField> result = hit.highlightFields();    
                //从设定的高亮域中取得指定域
                HighlightField titleField = result.get("title");  
                //取得定义的高亮标签
                Text[] titleTexts =  titleField.fragments();    
                //为title串值增加自定义的高亮标签
                String title = "";  
                for(Text text : titleTexts){    
                      title += text;  
                }
                //将追加了高亮标签的串值重新填充到对应的对象
                product.setTitle(title);
                //打印高亮标签追加完成后的实体对象
                System.out.println(product);
            }
            System.out.println("search success ..");
    
        }
    复制代码

     

     

    程序运行结果:

    复制代码
    [id=8,title=宏基<span style="color:red">Acer</span>,description=宏基Acer蜂鸟系列,price=5000.0,onSale=true,type=1,createDate=Mon Sep 30 13:46:41 CST 2013]
    [id=21,title=宏基<span style="color:red">Acer</span>,description=宏基Acer蜂鸟系列,price=5000.0,onSale=true,type=1,createDate=Mon Sep 30 13:48:17 CST 2013]
    [id=7,title=宏基<span style="color:red">Acer</span>,description=宏基Acer蜂鸟系列,price=5000.0,onSale=true,type=1,createDate=Mon Sep 30 11:38:50 CST 2013]
    [id=5,title=宏基<span style="color:red">Acer</span>乐0,description=<null>,price=4000.0,onSale=true,type=1,createDate=Mon Sep 30 16:35:23 CST 2013]
    [id=12,title=宏基<span style="color:red">Acer</span>乐1,description=<null>,price=4003.0,onSale=false,type=2,createDate=Mon Sep 30 16:35:23 CST 2013]
    [id=19,title=宏基<span style="color:red">Acer</span>乐2,description=<null>,price=4006.0,onSale=false,type=1,createDate=Mon Sep 30 16:35:23 CST 2013]
    [id=26,title=宏基<span style="color:red">Acer</span>乐3,description=<null>,price=4009.0,onSale=true,type=2,createDate=Mon Sep 30 16:35:23 CST 2013]
    [id=33,title=宏基<span style="color:red">Acer</span>乐4,description=<null>,price=4012.0,onSale=false,type=1,createDate=Mon Sep 30 16:35:23 CST 2013]
    复制代码

    从程序执行结果中我们可以看到,我们定义的高亮标签已经追加到指定的域上了.

    当搜索索引的时候,你搜索关键字包含了特殊字符,那么程序就会报错

    // fieldQuery 这个必须是你的索引字段哦,不然查不到数据,这里我只设置两个字段 id ,title
    String title = "title+-&&||!(){}[]^"~*?:\";
    title = QueryParser.escape(title);// 主要就是这一句把特殊字符都转义,那么lucene就可以识别
    searchRequestBuilder.setQuery(QueryBuilders.fieldQuery("title", title));


    转载请注明出处:[http://www.cnblogs.com/dennisit/p/3363851.html]

  • 相关阅读:
    SharePoint 2013 配置基于表单的身份认证
    SharePoint 2013 场解决方案包含第三方程序集
    SharePoint 2010 站点附加数据升级到SP2013
    SharePoint 2013 在母版页中插入WebPart
    SharePoint 2013 搭建负载均衡(NLB)
    SharePoint 部署解决方案Feature ID冲突
    SharePoint 2013 配置基于AD的Form认证
    SharePoint Server 2016 Update
    SharePoint 2013 为用户组自定义EventReceiver
    SharePoint 2013 JavaScript API 记录
  • 原文地址:https://www.cnblogs.com/softidea/p/6119329.html
Copyright © 2011-2022 走看看