• Solr分组查询


     项目中需要实时的返回一下统计的东西,因此就要进行分组,在获取一些东西,代码拿不出来,因此分享一篇,还是很使用的。

    facet搜索

    /**
        *
        * 搜索功能优化-关键词搜索
        * 搜索范围:商品名称、店铺名称
        *
        * @param keywords
        * @param skip
        * @param size
        * @return
        */
        @Override
        public List<KeywordSearchByName> searchByName(String keywords, Integer skip, Integer size) {
    
            solrServer = SolrContext.getServer();
            SolrQuery query = new SolrQuery();// 建立一个新的查询
            query.setQuery(keywords);
            query.setFacet(true);// 设置facet=on
            query.addFacetField(new String[] {"v1_groupId"});// 设置需要facet的字段
            query.setFacetLimit(20);// 限制facet返回的数量
            query.setFacetMissing(false);// 不统计null的值
            query.setFacetMinCount(1);// 设置返回的数据中每个分组的数据最小值,比如设置为1,则统计数量最小为1,不然不显示
    
            QueryResponse response = null;
            try {
                response = solrServer.query(query);
                System.out.println("查询时间:" + response.getQTime());
    
                List<FacetField> facets = response.getFacetFields();// 返回的facet列表
                for (FacetField facet : facets) {
                    // 获取分组字段FacetField
                    System.out.println(facet.getName());
                    System.out.println("----------------");
                    List<FacetField.Count> counts = facet.getValues();
                    for (FacetField.Count count : counts) {
    
                        System.out.println(count.getName() + ":" + count.getCount());
                    }
                    System.out.println();
                }
            } catch (SolrServerException e) {
                e.printStackTrace();
            }
            return null;
        }

    group搜索

    /**
        *
        * 搜索功能优化-关键词搜索
        * 搜索范围:商品介绍、店铺介绍、服务地址
        *
        * @param keywords
        * @param skip
        * @param size
        * @return
        */
        @Override
        public List<KeywordSearchByOther> searchByOther(String keywords, Integer skip, Integer size) {
    
            solrServer = SolrContext.getServer();
            SolrQuery query = new SolrQuery();// 建立一个新的查询
            query.setQuery(keywords);
            query.setParam(GroupParams.GROUP,true);//是否分组
            query.setParam(GroupParams.GROUP_FIELD,"v1_teacherId");//分组的域
            query.setParam(GroupParams.GROUP_LIMIT,"100");//每组显示的个数,默认为1
            query.setStart(skip); //起始索引值
            query.setRows(size);//显示几条数据
            QueryResponse response = null;
            try {
                response = solrServer.query(query, SolrRequest.METHOD.POST);
                Map<String, Integer> info = new HashMap<String, Integer>();
                GroupResponse groupResponse = response.getGroupResponse();
                if(groupResponse != null) {
                    List<GroupCommand> groupList = groupResponse.getValues();
                    for(GroupCommand groupCommand : groupList) {
                        List<Group> groups = groupCommand.getValues();
                        for(Group group : groups) {
                            info.put(group.getGroupValue(), (int)group.getResult().getNumFound());
                            System.out.println(group.getGroupValue()+(int)group.getResult().getNumFound());
                        }
                    }
                }
            }catch (SolrServerException e) {
                e.printStackTrace();
            }
            return null;
        }

    solr的group搜索

    按组查询的字段不能是int类型,必须是string类型,不然会包空指针异常,并且必须有q元素的查询,直接group.query不行

    solr查询非法字符处理

    非法字符串有这些
    && || ! ( ) { } [ ] ^ " ~ * ? : /

    过滤的方法很简单,用 进行转义
    solr 官方的处理方法
    https://svn.apache.org/repos/asf/lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/client/solrj/util/ClientUtils.java

    public static String escapeQueryChars(String s) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
          char c = s.charAt(i);
          // These characters are part of the query syntax and must be escaped
          if (c == '\' || c == '+' || c == '-' || c == '!'  || c == '(' || c == ')' || c == ':'
            || c == '^' || c == '[' || c == ']' || c == '"' || c == '{' || c == '}' || c == '~'
            || c == '*' || c == '?' || c == '|' || c == '&'  || c == ';' || c == '/'
            || Character.isWhitespace(c)) {
            sb.append('\');
          }
          sb.append(c);
        }
        return sb.toString();
      }

    solr的facet搜索

    facet的字段string获取名称乱码,int类型不乱吗

    solr搜索注意事项

    v1_modle:类型为int,下面搜索能搜索出数据

    <str name="q">普通 && v1_modle:1 && v1_fullpath:运动</str>

    v1_modle:类型为string,下面搜索不能搜索出数据

    <str name="q">普通 && v1_modle:1 && v1_fullpath:运动</str>

    solr按分类搜索结果集分页解决方案:

    // 服务
                                    if (count.getName().equals("1")) {
                                        // 按14个类目搜索返回条数
                                        long[] array = categroySearch(1, keywords);
                                        if (null != array && array.length > 0) {
                                            long totalnum = 0;
                                            for (int i = 0; i < array.length; i++) {
                                                totalnum = totalnum + array[i];
                                                if (array[i] > 0) {
                                                    if (skip == 0) {
                                                        // 判断size
                                                        if (totalnum >= size) {
                                                            // 获取下标i前的所有分类数据
                                                            // 按分类、关键词、group老师Id分组查询
                                                            System.out.print("skip = 0 ; break"+"===下标:"+i);
                                                            break;
                                                        } else {
                                                            continue;
                                                        }
                                                    }
                                                    if (skip > 0) {
                                                        // 判断skip、size
                                                        if ((totalnum - skip) > 0) {
                                                            if ((totalnum - skip) >= size) {
                                                                // 获取下标i前的所有分类数据
                                                                // 按分类、关键词、group老师Id分组查询
                                                                System.out.print("skip > 0 ; break"+"===下标:"+i);
                                                                break;
                                                            } else {
                                                                continue;
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                            if(totalnum == 0 || totalnum < skip){
                                                System.out.print("null");
                                            }else {
                                                System.out.print("all");
                                            }
                                        }
                                    }

    solr 高亮显示

    要用response.getHighlighting()接受转换高亮结果

    /**
        * solrJ搜索 高亮显示
        *
        * @author pudongping
        *
        * @param server
        *                    solr客户端
        * @param queryString
        *                    查询串
        * @param pageNum
        *                    分页 页码
        * @param pageSize
        *                    每页显示大小
        * @return
        */
        public static Page<QzoneArticle> queryComHighlight(SolrServer server, String queryString, int pageNum,int pageSize){
            SolrQuery query = new SolrQuery();
            query.setQuery(queryString);
            query.setHighlight(true);//开启高亮功能
            query.addHighlightField("description");//高亮字段
            query.addHighlightField("keywords");
            query.setHighlightSimplePre("<font color='red'>");//渲染标签
            query.setHighlightSimplePost("</font>");//渲染标签
            query.setStart((pageNum-1)*pageSize);
            query.setRows(pageSize);
            QueryResponse response = null;
            try {
                response = server.query(query);
            } catch (SolrServerException e) {
                e.printStackTrace();
                return null;
            }
            //查询结果集
            SolrDocumentList lists = response.getResults();
    
            //对象结果集
            List<QzoneArticle> items = new ArrayList<QzoneArticle>();
    
            //查询到的记录总数
            long totalRow = Long.valueOf(response.getResults().getNumFound()).intValue();
    
            String tmpId = "";
    
            Map<String,Map<String,List<String>>> highlightMap=response.getHighlighting();
            for (SolrDocument solrDocument : lists) {
                QzoneArticle at = new QzoneArticle();
                tmpId=solrDocument.getFieldValue("id").toString();
                at.setId(tmpId);
                at.setAuthor(solrDocument.getFieldValue("author").toString());
                List<String> descList=highlightMap.get(tmpId).get("description");
                List<String> keywsList=highlightMap.get(tmpId).get("keywords");
                if(descList!=null && descList.size()>0){
                    at.setDescription(descList.get(0));
                }else{
                    //获取并设置高亮的字段title
                    at.setDescription(solrDocument.getFieldValue("description").toString());
                }
                if(keywsList!=null && keywsList.size()>0){
                    at.setKeywords(keywsList.get(0));
                }else{
                    at.setKeywords(solrDocument.getFieldValue("keywords").toString());
                }
                items.add(at);
            }
    
            //填充page对象
            return new Page<QzoneArticle>(pageNum, pageSize, totalRow, items);
    
        }

    solr高亮,文本太多,想截取关键词前后多少字的一段文本

    hl.fl
    hl.fl
    是说明你要关键字的摘要在那个field中取,我们一般是content字段。 hl.useFastVectorHighlighter
    该参数很重要,如果你不看代码,是很难发现他的好处,默认是false,即文本段的划分是按每50个字符来划分,然后在这个50个字符中取关键字相关的摘要,摘要长度为100,参考后面的参数(hf.fragsize),如果我们在参数中指定值为true,那么SOLR会根据关键词的在文本中的偏移量来计算摘要信息,前提是你的field要加上 termPositions="true" termOffsets="true"
    这两项。
    hl.snippets
    hl.snippets
    参数是返回高亮摘要的段数,因为我们的文本一般都比较长,含有搜索关键字的地方有多处,如果hl.snippets
    的值大于1的话,会返回多个摘要信息,即文本中含有关键字的几段话,默认值为1,返回含关键字最多的一段描述。solr会对多个段进行排序。
    hl.fragsize
    hl.fragsize
    参数是摘要信息的长度。默认值是100,这个长度是出现关键字的位置向前移6个字符,再往后100个字符,取这一段文本。
    hl.boundaryScanner、hl.bs.maxScan、hl.bs.chars
    boundaryScanner
    是边界扫描,就是怎么取我们高亮摘要信息的起始位置和结束位置,这个是我们摘要信息的关键,因为我们模式高亮摘要的开始和结束可能是某句话中截段的。上面这三个参数需要放在一起来说明,因为后两个是在我们没有给hl.boundaryScanner
    设定值,即默认值时才会有效,对应的class为:SimpleBoundaryScanner,上面讲了hl.fragsize
    参数,
    SimpleBoundaryScanner会根据hl.fragsize
    参数决定的关键字的起始偏移量和结束偏移量,重新计算摘要的起始偏移量,首先说开始偏移量,源码如下:

    public int findStartOffset(StringBuilder buffer, int start) {
        // avoid illegal start offset
        if( start > buffer.length() || start < 1 ) return start;
    
        //maxScan是hl.bs.maxScan的值,它是说明从关键字出现的位置往前6个字符开始向前,在maxScan个字符内找是否出 现一个
    
        //一个由参数hl.bs.chars指定的分界符。即从这里作为摘要的起始偏移。 如果往前maxScan个字符内没有发现指定的字符,
    
        //则按起始便宜为start,即关键词往前的6个字符。
    
        int offset, count = maxScan;
        for( offset = start; offset > 0 && count > 0; count-- ){
          // found?
          if( boundaryChars.contains( buffer.charAt( offset - 1 ) ) ) return offset;
          offset--;
        }
        // if we scanned up to the start of the text, return it, its a "boundary"
        if (offset == 0) {
          return 0;
        }
        // not found
        return start;
      }

    结束便宜量和计算起始偏移量是一样的,只不过是从关键词的位置往后100个字符的位置往后找分隔符,maxScan的默认值为10,hl.sc.chars
    的默认值为.,!?
    hl.boundaryScanner
    参数我们不指定值时,按上面的算法计算高亮摘要信息,但solr还提供了一种算法,即breakIterator,我们在请求参数中添加&hl.boundaryScanner=breakIterator时生效,这是solr通过java jdk的BreakIterator来计算分界符的。他相关的参数为,hl.bs.type,这个是主要的参数,决定BreakIterator怎么划分界定符,值有:CHARACTER, WORD, SENTENCE and LINE,SENTENCE 是按句子来划分,即你高亮摘要信息是一个完整的句子,而不会被截断。
    solr高亮的配置参数说明
    参数详细说明:
    hl.fl
    : 用空格或逗号隔开的字段列表。要启用某个字段的highlight功能,就得保证该字段在schema中是stored。如果该参数未被给出,那么就会高亮默认字段 standard handler会用df参数,dismax字段用qf参数。你可以使用星号去方便的高亮所有字段。如果你使用了通配符,那么要考虑启用hl.requiredFieldMatch选项。
    hl.requireFieldMatch
    :如果置为true,除非该字段的查询结果不为空才会被高亮。它的默认值是false,意味着它可能匹配某个字段却高亮一个不同的字段。如果hl.fl使用了通配符,那么就要启用该参数。尽管如此,如果你的查询是all字段(可能是使用copy-field 指令),那么还是把它设为false,这样搜索结果能表明哪个字段的查询文本未被找到hl.usePhraseHighlighter:如果一个查询中含有短语(引号框起来的)那么会保证一定要完全匹配短语的才会被高亮。hl.highlightMultiTerm如果使用通配符和模糊搜索,那么会确保与通配符匹配的term会高亮。默认为false,同时hl.usePhraseHighlighter要为true。
    hl.snippets
    :这是highlighted片段的最大数。默认值为1,也几乎不会修改。如果某个特定的字段的该值被置为0(如f.allText.hl.snippets=0),这就表明该字段被禁用高亮了。你可能在hl.fl=*时会这么用。hl.fragsize:每个snippet返回的最大字符数。默认是100.如果为0,那么该字段不会被fragmented且整个字段的值会被返回。大字段时不会这么做。
    hl.mergeContiguous
    :如果被置为true,当snippet重叠时会merge起来。
    hl.maxAnalyzedChars
    :会搜索高亮的最大字符,默认值为51200,如果你想禁用,设为-1
    hl.alternateField
    :如果没有生成snippet(没有terms 匹配),那么使用另一个字段值作为返回。
    hl.maxAlternateFieldLength
    :如果hl.alternateField启用,则有时需要制定alternateField的最大字符长度,默认0是即没有限制。所以合理的值是应该为hl.snippets * hl.fragsize这样返回结果的大小就能保持一致。
    hl.formatter
    :一个提供可替换的formatting算法的扩展点。默认值是simple,这是目前仅有的选项。显然这不够用,你可以看看org.apache.solr.highlight.HtmlFormatter.java 和 solrconfig.xml中highlighting元素是如何配置的。注意在不论原文中被高亮了什么值的情况下,如预先已存在的em tags,也不会被转义,所以在有时会导致假的高亮。
    hl.fragmenter
    :这个是solr制定fragment算法的扩展点。gap是默认值。regex是另一种选项,这种选项指明highlight的边界由一个正则表达式确定。这是一种非典型的高级选项。为了知道默认设置和fragmenters (and formatters)是如何配置的,可以看看solrconfig.xml中的highlight段。regex 的fragmenter有如下选项:
    hl.regex.pattern
    :正则表达式的pattern
    hl.regex.slop
    :这是hl.fragsize能变化以适应正则表达式的因子。默认值是0.6,意思是如果hl.fragsize=100那么fragment的大小会从40-160.

    solr搜索只关键词高亮,分类关键词不高亮实现

    关键词在高亮的前面先setQuery(“keywords”),然后在高亮封装完的后面query.setFilterQueries("过滤的分类词")

    public Map<String,List<PlayService>> searchPlayCategory(String keywords, Integer cursor, Integer skip, Integer size) {
    
            Map<String,List<PlayService>> mapplays = new HashMap<String,List<PlayService>>();
            List<String> strlist = getCategoryNameBycursorPlay(cursor);
            if (null != strlist && strlist.size() > 0) {
                for (int j = 0; j < strlist.size(); j++) {
                    List<PlayService> plays = new ArrayList<>();
                    StringBuffer sb = new StringBuffer(128);
                    sb.append("'"" + keywords + ""' && v1_modle:2 ");
                    SolrQuery query = new SolrQuery();// 建立一个新的查询
                    query.setQuery(sb.toString());
                    query.setHighlight(true).setHighlightSimplePre("<span style='color:#FA022C;'>")
                        .setHighlightSimplePost("</span>");
                    query.addHighlightField("v1_serviceTitle");//高亮字段
                    query.setParam("hl.fragsize","15");
                    query.setParam("hl.usePhraseHighlighter","true");
                    query.setFilterQueries(" v1_fullpath:" + strlist.get(j));
                    QueryResponse response = null;
                    try {
                        response = SolrContext.getServer().query(query, SolrRequest.METHOD.POST);
                        Map<String, Map<String, List<String>>> hightlight = response.getHighlighting();
                        plays = response.getBeans(PlayService.class);
                        for (int i = 0; i < plays.size(); i++) {
                            //hightlight的键为Item的id,值唯一,我们设置的高亮字段为title
                            if (null != hightlight.get(plays.get(i).getServiceSkuId()).get("v1_serviceTitle")) {
                                String hlString = hightlight.get(plays.get(i).getServiceSkuId()).get("v1_serviceTitle").toString();
                                if (null != hlString) {
                                    plays.get(i).setServiceName(hlString.replaceAll("[\[\]]",""));
                                }
                            }
                        }
                    } catch (SolrServerException e) {
                        e.printStackTrace();
                    }
                    if (null != plays && plays.size() > 0) {
                        mapplays.put(strlist.get(j), plays);
                    }
                }
            }
            return mapplays;
        }
    作者:wangxiaoda
    链接:https://www.jianshu.com/p/41364bf865fc

  • 相关阅读:
    横冲直撞vue(第六篇):vue之过滤器、es6中填充字符串、es6新增的padStart()方法和padEnd()方法、vue自定义键盘修饰符、vue自定义全局指令
    leetcode的奇妙冒险(python3)系列:leetcode 283. Move Zeroes
    横冲直撞vue(第五篇):事件修饰符、指令系统综合案例
    横冲直撞vue(第四篇):v-model、指令系统总结、指令系统示例轮播图实现、指令系统示例跑马灯效果实现、在vue中使用样式的方式
    横冲直撞vue(第三篇):vue中template的三种写法、v-bind、v-on、更新元素的指令v-text与v-html、条件渲染指令v-if 与v-show、v-for
    横冲直撞vue(第二篇):什么是vue?框架和库的区别、vue的优点、vue的使用、使用vue实例化对象
    横冲直撞vue(第一篇):常用的ES6语法
    nodejs(第五篇):npm常用命令、包说明文件package.json、packjson-lock.json文件、使用nodemon插件、nrm的安装与使用
    最详细的个人博客教程搭建教程,最快5分钟快速搭建简约风格博客
    面试问了解Linux内存管理吗?10张图给你安排的明明白白!
  • 原文地址:https://www.cnblogs.com/dalianpai/p/11933946.html
Copyright © 2020-2023  润新知