技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> 算法 --> SolrQuery挖掘–单维度聚合分析

SolrQuery挖掘–单维度聚合分析

浏览:2368次  出处信息

单维度聚合分析

为什么选择搜索引擎

单维度聚合分析应该是各种分析统计中最为简单、直接。
对于主动搜索、被动搜索一体的应用场景,有登录和无登陆等统一兼顾。并且提供接口服务,按需返回维度信息,并且可以复用。
无疑采取搜索引擎,依赖搜索引擎的facet统计功能,最为直接、快捷、有效、低沉本。前提是对搜索引擎比较熟悉,否则光一个
搜索引擎就折腾死人了。

单维度聚合分析意义

单维度分析意义主要在掌握数据属性、用户属性、热点发现。
例如:某个产品上某个用户一段时间搜索词聚合,然后对聚合词语义分析,将可以分析出该用户的某些历史偏好、行为特征、消费
倾向、社区角色等。
例如:一段时间内产品上用户在搜什么,那些是热点词,是否与运营活动相关,是否是产品的重点词范畴等。
例如:将关键词、时间、产品倒排起来,那么就可以知道任何时间段内,具体产品活跃的关键词分布,间接知晓产品的“语义集合”
例如:将关键词、用户、时间倒排起来,那么很容易知晓那些词偏女性、那些词偏男性、那些词中性,用户那个时候搜的多、是那些词
例如:将关键词、排序、翻页、命中倒排起来,那么很容易发现点击热点、超时分析等。
。。。。
太多了

陷阱

大家都关注结果去了,没有人喜欢过程,尤其是周期性、长期的过程。在淘宝上成交量、客单价为主题的大环境,任何和交易不相关
、任何不能直接影响交易、任何只是提升用户细微体验等等工作,都是一个“弱势”需求,甚至等于不是需求。
所以,技术即使实现,也不见得有人会关注、有人去用。KPI中不会因为用户体验而打分,KPI中不会因为改善排序效果而肯定。
因为本身这些不好评估效果,特别是短期内的效果。更本质的可能是这些“无关交易”!

单维度聚合关键问题

维度的选择

既然是单维度聚合,那么维度的选择就非常重要了。这个需要不是技术一方面说的算,更多的依赖业务。
而往往习惯了运营为主、人肉、经验为主的 淘宝居多业务,对交易之位的属性关注度明显的不在意。
也甚至出现,计算出来的结果会在 白名单、黑名单过滤下,面目全非。
通常基本的维度不可少:时间、业务、人、关键词等。也即时间、地点、人物、事件。

格式化

输入就是线上日志,输出就是格式化文档或者倒排索引结构。
在输入和输出之间就是转换。转换的过程其实非常麻烦的问题,只看一端只觉得问题很easy!
麻烦之处:

(1)提取规则

日志总是有许多莫名其妙的格式、内容、乱码。很难有一个100%的规则,满足所有请求日志。
即使有,也很难很容易的扩展到其他应用。例如solr 日志格式是有规律的,但是用户内容不一定有规律。
基于文本标签提取,自然会遇到内容的标签问题。提取完毕之后,schema结构具体应用是不一样的。

(2)提取速度

越精细越耗时,并且java String对象处理起来比较方便,却速度上远远低于char,而char处理不是很方便。
对应solr query log 还是建议采取char为主、StringBuidler为核心变量。

(3)适应性

一开始都是追求100%解析通过,实际总有那么一些内容,搅合常规处理方法。为了适应这些非常规的请求,
往往会将之前的处理规则打破或者添加更多条件,然后整体性能突然下降。建议:能处理的快速处理,不能处理的
单独输入到一个文本,对于这些非常规的特殊处理。

单维度聚合实现样例

对于终搜 solr 日志
输入 2012-08-09 14:50:33,396 INFO [org.apache.solr.core.SolrCore] - [search4product-0]
webapp=null path=/select params={q=+supplier_id%
3A649289&sort=weight1+desc&rows=30&start=0&facet=true
&facet.field=cat_path&hl.usePhraseHighlighter=false&echoParams=explicit&hl=true
&hl.fl=title&hl.requireFieldMatch=true&hl.simple.pre=
&hl.simple.post=&hl.snippets=3&hl.fragsize=2000&timeAllowed=2500}
hits=1762 status=0 QTime=123
解码
2012-08-09 14:50:33,396 INFO [org.apache.solr.core.SolrCore] - [search4product-0]
webapp=null path=/select params={q=+supplier_id:649289&sort=weight1
desc&rows=30&start=0&facet=true&facet.field=cat_path&hl.usePhraseHighlighter=false
&echoParams=explicit&hl=true&hl.fl=title&hl.requireFieldMatch=true&hl.simple.pre=
&hl.simple.post=&hl.snippets=3&hl.fragsize=2000&timeAllowed=2500}
hits=1762 status=0 QTime=123
 public class QueryRowToStructureQuery {
 
    
//private static String  splitTag="#&";

    protected static Log log = LogFactory.getLog( QueryRowToStructureQuery.class);
 public static String doParseDemoV2(String inputStr) {

            if (inputStr == null)
                        return null;

            // long start= System.nanoTime();
                
StringBuilder sb = new StringBuilder();

            sb.append(inputStr.subSequence(0, 10)).append("T").append(inputStr.subSequence(11, 19)).append("Z").append( DefaultParams.SPLITTAG );//time
 

            char[] chars = inputStr.toCharArray(); 

 int i = 64;
                int tep = i;
                while (chars[i] != ']')
                        i++;
 sb.append(inputStr.subSequence(tep, i)).append(DefaultParams.SPLITTAG);// searviceName
                                                                                                                                        // extract 

 i = getItem(chars, i, sb);// 递归抽取查询串
 

            String[] temp=inputStr.subSequence(i + 2, inputStr.length()).toString().trim().split(" ");
                if(temp[0].contains("hits")){

                            sb.append(temp[0].replaceAll("=", ":")).append(DefaultParams.SPLITTAG);
                                sb.append(temp[2].replaceAll("=", ":")).append("\r\n");// hits status QTime
                                // System.out.println("doParseDemoV2_timeCost="+(System.nanoTime()-start));
                                //    System.out.println(sb.toString());

                            return sb.toString();
                }else{
                        log.error(inputStr);// 针对无法处理或者处理格式不对的抛出异常
 return null;
                }
        }
  

 private static int getItem(char[] chars, int i, StringBuilder sb) {

            while (chars[i] != '{') {
                        i++;
                }
 

            boolean changed = true;
                
int pos = 0;

            while (true && chars[i] != '}') {

                    i++;
                        if (changed) { pos = i;
                                changed = false;
                        }
                        
// System.out.println(chars[i]);
                        // int deep=1;
                        
boolean stop = true;
                        
if (chars[i] == '&') {
                                StringBuilder sbTemp = new StringBuilder();

for (int t = pos; t < i; t++)
                                        if (chars[t] == '(' || chars[t] == ')') {
                                        } else
                                                sbTemp.append(chars[t]);
                                changed = true;
                                String temp = sbTemp.toString();

//                                if (temp.getBytes().length != temp.length())
// sb.append("CW_").append(temp.trim()).append(DefaultParams.SPLITTAG);
//                            else 
                                        if (temp.contains(":"))
                                        sb.append(temp.trim()).append(DefaultParams.SPLITTAG);
                                
else if (temp.contains("sort"))
                                        sb.append(temp.trim().replaceAll("=", ":"))
                                                        .append(DefaultParams.SPLITTAG);
                                else
                                        ;
                                // System.out.println(sbTemp.toString());
                        }
 

                    if (chars[i] == '+') {
                                if (changed) {

                                    pos = i;
                                        i++;
                                        changed = false;
                                }
                                while (true ) {
                                        if (chars[i] == '+' || chars[i] == '&' || chars.length < i)
                                                break;
                                        else
                                                i++;
                                }

                            StringBuilder sbTemp = new StringBuilder();
                                
for (int t = pos; t < i; t++) {
 if (chars[t] == '(' || chars[t] == ')' ) {
                                        } else
                                                sbTemp.append(chars[t]);
 
                                }
 changed = true;
                                String temp = sbTemp.toString();
                                // System.out.println(temp);
//                            if (temp.getBytes().length != temp.length())
//                                    sb.append("CW_").append(temp.trim()).append(DefaultParams.SPLITTAG);
//                            else 
                                        if (temp.contains(":"))
                                        sb.append(temp.trim()).append(DefaultParams.SPLITTAG);

                            else if (temp.contains("sort"))
                                        sb.append(temp.trim().replaceAll("=", ":"))
                                                        .append(DefaultParams.SPLITTAG);
                                else
                                        ;
                        }
                }
                return i;
        }
提取输出 2012-08-09T14:50:33Z#&search4product-0#&supplier_id:649289#&sort:weight1 desc#&hits:1762#&QTime:123

构建solr document
  public static AddUpdateCommand generateAddCommand(String query, IndexSchema schema) {
                AddUpdateCommand addCmd = new AddUpdateCommand();

            addCmd.allowDups = false;
                addCmd.overwriteCommitted = true;
                
addCmd.overwritePending   = true;
                
SolrInputDocument solrDoc = new SolrInputDocument();

            solrDoc.clear();
 
                //solrDoc.setDocumentBoost(DEFAULT_DOCUMENT_BOOST);   
                String[] items = query.split( DefaultParams.SPLITTAG );
                //logger.warn( query );               
 
                solrDoc.addField("reqtime", items[0]);
                
solrDoc.addField("sername", items[1]);
 

            for (int i=2;i<items.length; i++) {
 String[] keyPair= items[i].split(":");

                if ( schema.getFieldOrNull( keyPair[0].toString()) == null ) {
 // 忽略多余的字段,没有在schema.xml中配置的字段

                    continue;
                    }
                    
if ( keyPair[1] == null ||(keyPair[1] != null && (" ").equals(keyPair[1])) ) {
                        continue;
                    }
                    solrDoc.addField(keyPair[0], keyPair[1]);

            }      
                addCmd.solrDoc = solrDoc;
                
try{ addCmd.doc = DocumentBuilder.toDocument( solrDoc, schema );
                
}catch(Exception e){

                logger.error(solrDoc, e);
                } return addCmd;
                }

建议继续学习:

  1. 新闻聚合之Google news模式与 Techmeme模式    (阅读:1309)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1