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;
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • facet搜索 group搜索 solr的group搜索 按组查询的字段不能是int类型,必须是string类型,...
    wangxiaoda阅读 4,573评论 0 1
  • 科多大数据带你看,小白怎么快速学习solr 一、查询参数说明 在做solr查询的时候,solr提供了很多参数来扩展...
    大数据在说话阅读 384评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,637评论 18 139
  • 这世间不如意之事十之八九,若能在刚好的时间遇到刚好的人结一段刚好的缘,这便是缘分了,但大多数的时候,我们却总是遗憾...
    池塘水绿阅读 704评论 2 12
  • 1. 方方和细弟今天结束夏令营之旅,傍晚会回到家里。 早上,我和方方通电话的时候,顺便问她: 晚饭我们是在家里吃呢...
    文晓玲阅读 138评论 3 4