solr5项目实战详解,分布式缓存,全文检索

说一下大体思路,电商类网站,由于老项目数据库设计很不合理,一些查询涉及的表过多,导致查询速度异常缓慢,在不修改架构设计和源码上,做了一下处理。

solr+eh ,使用eh缓存关联数据,再用solr查询速度,文章偏向小白文,大神见笑。很多设计不完善,实现功能为主。

一、配置缓存功能

结合我之前博文的eh文章配置,让项目启动后自动拉取数据存入缓存。

首先建立一个监听类,实现项目启动后调用。

StartupListener.java

public class StartupListener implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
       //缓存数据
    }

公共容器xml配置添加

<bean id="startupListener" class="StartupListener类路径"></bean>

封装了EH工具类

EHUtil.java

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;

public class EHUtil {

    private static final CacheManager manager = new CacheManager("src/main/resources/ehcache.xml");

    public static void setCache(String cacheName,String key,Object value){
        Cache cache = manager.getCache(cacheName);
        Element element = new Element(key,value);
        cache.put(element);
    }

    public static Object getCache(String cacheName,String key){
        Cache cache = manager.getCache(cacheName);
        Element element = cache.get(key);
        if (element != null) {
            return element.getValue();
        }
        return null;
    }

    public static boolean removeCache(String cacheName,String key){
        Cache cache = manager.getCache(cacheName);

        return cache.remove(key);
    }

    public static int getSize(String cacheName){
        Cache cache = manager.getCache(cacheName);

        return cache.getSize();
    }

    public static long getMemoryStoreSize(String cacheName){
        Cache cache = manager.getCache(cacheName);
        return cache.getMemoryStoreSize();
    }
}

定义 getCache 返回类型为Object 如果需要返回javaBean,需要实现序列化

然后在项目Service内调用,保证操作dao层数据修改同步到EH缓存里,具体根据业务编写。

二、solr检索配置

创建solr工具类

SolrUti.java

import java.util.ArrayList;
import java.util.List;

import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.ModifiableSolrParams;

import com.penuel.mythopoetms.model.SolrCode;

public class SolrUtil {

    //填写你得solr服务器的core地址,例如: http://XXX/solr/db
    private static final String URL = Constants.get("SOLR_URL");

    private static HttpSolrClient server = null;

    static{
        server = new HttpSolrClient(URL);
    }

    public static void addDoc(SolrInputDocument doc){
        try {
            UpdateResponse response = server.add(doc);
            // 提交
            server.commit();
//            System.out.println("########## Query Time :" + response.getQTime());
//            System.out.println("########## Elapsed Time :" + response.getElapsedTime());
//            System.out.println("########## Status :" + response.getStatus());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void addDocs(Object key,List<Object> objs){
        List<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();

        for(Object obj:objs ){
            SolrInputDocument doc = new SolrInputDocument();

            doc.addField(SolrCode.id.code, key);
            doc.addField(SolrCode.title.code, obj);

            docs.add(doc);
        }

        try {
            server.add(docs);
            // 提交
            server.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void byAddDocs(List<SolrInputDocument> docs){
        try {
            server.add(docs);
            // 提交
            server.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void removeDoc(String key){
        try {
            server.deleteById(key);
            server.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void removeQuery(String key){
        try {
            server.deleteByQuery(key);
            server.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static SolrDocumentList queryPage(ModifiableSolrParams params){

        try {
            QueryResponse response = server.query(params);
            SolrDocumentList list = response.getResults();

//            System.out.println("########### 总共 : " + list.getNumFound() + "条记录");
//            System.out.println("########### 总共 : " + response.getQTime()+ "毫秒");
//
//            for (SolrDocument doc : list) {
//                System.out.println("######### id : " + doc.get("id") + "  title : " + doc.get("title"));
//            }

            return list;
        } catch (SolrServerException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static SolrDocument queryById(ModifiableSolrParams params){

        try {
            QueryResponse response = server.query(params);
            SolrDocumentList list = response.getResults();
            if(list.size()>0){
                return list.get(0);
            }
        } catch (SolrServerException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String getIds(SolrDocumentList list){
        StringBuffer sb = new StringBuffer();
        for(SolrDocument doc:list){
            String sss = ((String) doc.get("id")).replaceAll("\\D+", "");
            if(sb.length()==0){
                sb.append(sss);
                continue;
            }
            sb.append(","+sss);
        }
        return sb.toString();
    }
}

---------------------------------------------------------------------------------------------------------------------------------------------------------------------

配置完成,现在理顺一下项目业务,

例:获取一个商品列表,商品名和设计师名,两个字段需要检索,然后提供根据更新时间排序,并实现分页。

分析:前面说了,数据库设计结构为 (A表 B表 AB表)一但这种表多起来, 查询会很慢。

数据库设计解决:A: 商品表,B:设计师表,C:分类,D:品牌。 可见设计库设计的不合理,在不修改原架构上进行处理。

1.建立缓存。把 AB,AC,AD,B,C,D 等表 建立缓存

配置统一标准规则key来主键查询缓存,如(XXX+A表的id)这样就可以根据A表id直接提取缓存数据。

创建枚举类

CacheCode.java

public enum CacheCode {
    Cache("myCache"),designer("designerKEY"),brand("brandKEY")
    ,designerI("designerIKEY"),brandI("brandIKEY")
    ,cate("cateKEY"),cateI("cateIKEY");

    public String code;
    private CacheCode(String code){
        this.code=code;
    }
}

创建好后按照规则 启动拉取数据存入缓存,修改之前的监听类

 StartupListener.java

import java.util.ArrayList;
import java.util.List;

import org.apache.solr.common.SolrInputDocument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Service;

import com.penuel.mythopoetms.model.Brand;
import com.penuel.mythopoetms.model.CacheCode;
import com.penuel.mythopoetms.model.Category;
import com.penuel.mythopoetms.model.Designer;
import com.penuel.mythopoetms.model.Item;
import com.penuel.mythopoetms.model.ItemBrand;
import com.penuel.mythopoetms.model.ItemCate;
import com.penuel.mythopoetms.model.ItemDesigner;
import com.penuel.mythopoetms.model.ItemOther;
import com.penuel.mythopoetms.service.BrandService;
import com.penuel.mythopoetms.service.CategoryService;
import com.penuel.mythopoetms.service.DesignerService;
import com.penuel.mythopoetms.service.ItemBrandService;
import com.penuel.mythopoetms.service.ItemCateService;
import com.penuel.mythopoetms.service.ItemDesignerService;
import com.penuel.mythopoetms.service.ItemHelpService;
import com.penuel.mythopoetms.service.ItemOtherService;
import com.penuel.mythopoetms.service.ItemService;

@Service
public class StartupListener implements ApplicationListener<ContextRefreshedEvent> {

    @Autowired
    private DesignerService designerService;
    @Autowired
    private BrandService brandService;
    @Autowired
    private ItemDesignerService itemDesignerService;
    @Autowired
    private ItemBrandService itemBrandService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private ItemCateService itemCateService;
    @Autowired
    private ItemService itemService;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        try {
            //设计师关联表
            List<ItemDesigner> idList = itemDesignerService.list();
            if(idList!=null&&idList.size()>0){
                for(ItemDesigner idr:idList){
                    EHUtil.setCache(CacheCode.Cache.code, CacheCode.designerI.code+idr.getItemId(), idr.getDesignerId());
                }
            }

            //设计师
            List<Designer> dlist = designerService.listDesigners();
            if(dlist!=null&&dlist.size()>0){
                for(Designer designer:dlist){
                    EHUtil.setCache(CacheCode.Cache.code, CacheCode.designer.code+designer.getId(), designer);
                }
            }

            //品牌关联表
            List<ItemBrand> ibList = itemBrandService.list();
            if(ibList!=null&&ibList.size()>0){
                for(ItemBrand ib:ibList){
                    EHUtil.setCache(CacheCode.Cache.code, CacheCode.brandI.code+ib.getItemId(), ib.getBrandId());
                }
            }

            //品牌
            List<Brand> blist = brandService.listBrands();
            if(blist!=null&&blist.size()>0){
                for(Brand brand:blist){
                    EHUtil.setCache(CacheCode.Cache.code, CacheCode.brand.code+brand.getId(), brand);
                }
            }

            //标签关联
            List<ItemCate> icList = itemCateService.list();
            if(icList!=null&&icList.size()>0){
                for(ItemCate ic:icList){
                    EHUtil.setCache(CacheCode.Cache.code, CacheCode.cateI.code+ic.getItemId(), ic.getCateId());
                }
            }

            //标签
            List<Category> cList = categoryService.listCategories();
            if(cList!=null&&cList.size()>0){
                for(Category category:cList){
                    EHUtil.setCache(CacheCode.Cache.code, CacheCode.cate.code+category.getId(), category);
                }
            }
    }
}

Service自行添加编写,不做描述。

下面开始solr相关配置

2.编写业务工具类,用于增删改查 solr 索引,

首先,设计好solr索引库要存的字段。前面讲过:获取一个商品列表,商品名和设计师名,两个字段需要检索,然后提供根据更新时间排序,并实现分页

所以solr存储数据的格式应该是这样的

[‘ltime:‘更新时间‘,id:‘itemId+商品ID‘,‘title:‘商品名称‘,‘name‘:‘设计师名字‘]

其中id为 唯一,相同id会覆盖操作,这里不懂solr配置的可看我前面的文章配置,包括中文分词

先从建立索引开始入手。同样建立solr的枚举类统一key规则

SolrCode.java

public enum SolrCode {
    id("id"),title("title"),ltime("last_modified"),name("name");

    public String code;
    private SolrCode(String code){
        this.code=code;
    }
}

编写业务类建立索引

ItemHelpService.java

import java.io.IOException;
import java.io.StringReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;

import com.penuel.mythopoetms.model.CacheCode;
import com.penuel.mythopoetms.model.Designer;
import com.penuel.mythopoetms.model.Item;
import com.penuel.mythopoetms.model.SolrCode;
import com.penuel.mythopoetms.utils.EHUtil;
import com.penuel.mythopoetms.utils.SolrUtil;

public class ItemHelpService {

    /**
     * @param date 时间
     * @param strs 多个参数
     * @return
     * @throws ParseException
     */
    public static SolrInputDocument addDocsHelp(Date date,String ...strs) throws ParseException{
        SimpleDateFormat format =  new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); 

        SolrInputDocument doc = new SolrInputDocument();

        doc.addField(SolrCode.ltime.code,date);
        doc.addField(SolrCode.id.code, strs[0]);
        doc.addField(SolrCode.title.code, strs[1]);
        doc.addField(SolrCode.name.code, strs[2]);

        return doc;
    }

}

编写完成后 修改 StartupListener 启动项目并建立索引

StartupListener.java

import java.util.ArrayList;
import java.util.List;

import org.apache.solr.common.SolrInputDocument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Service;

import com.penuel.mythopoetms.model.Brand;
import com.penuel.mythopoetms.model.CacheCode;
import com.penuel.mythopoetms.model.Category;
import com.penuel.mythopoetms.model.Designer;
import com.penuel.mythopoetms.model.Item;
import com.penuel.mythopoetms.model.ItemBrand;
import com.penuel.mythopoetms.model.ItemCate;
import com.penuel.mythopoetms.model.ItemDesigner;
import com.penuel.mythopoetms.model.ItemOther;
import com.penuel.mythopoetms.service.BrandService;
import com.penuel.mythopoetms.service.CategoryService;
import com.penuel.mythopoetms.service.DesignerService;
import com.penuel.mythopoetms.service.ItemBrandService;
import com.penuel.mythopoetms.service.ItemCateService;
import com.penuel.mythopoetms.service.ItemDesignerService;
import com.penuel.mythopoetms.service.ItemHelpService;
import com.penuel.mythopoetms.service.ItemOtherService;
import com.penuel.mythopoetms.service.ItemService;

@Service
public class StartupListener implements ApplicationListener<ContextRefreshedEvent> {

    @Autowired
    private DesignerService designerService;
    @Autowired
    private BrandService brandService;
    @Autowired
    private ItemDesignerService itemDesignerService;
    @Autowired
    private ItemBrandService itemBrandService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private ItemCateService itemCateService;
    @Autowired
    private ItemOtherService itemOtherService;
    @Autowired
    private ItemService itemService;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        try {
            //设计师关联表
            List<ItemDesigner> idList = itemDesignerService.list();
            if(idList!=null&&idList.size()>0){
                for(ItemDesigner idr:idList){
                    EHUtil.setCache(CacheCode.Cache.code, CacheCode.designerI.code+idr.getItemId(), idr.getDesignerId());
                }
            }

            //设计师
            List<Designer> dlist = designerService.listDesigners();
            if(dlist!=null&&dlist.size()>0){
                for(Designer designer:dlist){
                    EHUtil.setCache(CacheCode.Cache.code, CacheCode.designer.code+designer.getId(), designer);
                }
            }

            //品牌关联表
            List<ItemBrand> ibList = itemBrandService.list();
            if(ibList!=null&&ibList.size()>0){
                for(ItemBrand ib:ibList){
                    EHUtil.setCache(CacheCode.Cache.code, CacheCode.brandI.code+ib.getItemId(), ib.getBrandId());
                }
            }

            //品牌
            List<Brand> blist = brandService.listBrands();
            if(blist!=null&&blist.size()>0){
                for(Brand brand:blist){
                    EHUtil.setCache(CacheCode.Cache.code, CacheCode.brand.code+brand.getId(), brand);
                }
            }

            //标签关联
            List<ItemCate> icList = itemCateService.list();
            if(icList!=null&&icList.size()>0){
                for(ItemCate ic:icList){
                    EHUtil.setCache(CacheCode.Cache.code, CacheCode.cateI.code+ic.getItemId(), ic.getCateId());
                }
            }

            //标签
            List<Category> cList = categoryService.listCategories();
            if(cList!=null&&cList.size()>0){
                for(Category category:cList){
                    EHUtil.setCache(CacheCode.Cache.code, CacheCode.cate.code+category.getId(), category);
                }
            }
            //商品url
            List<ItemOther> ioList = itemOtherService.list();
            if(ioList!=null&&ioList.size()>0){
                for(ItemOther io:ioList){
                    EHUtil.setCache(CacheCode.Cache.code, CacheCode.otherI.code+io.getItemId(), io.getUrlDetail());
                }
            }

            //商品or设计师索引
            //[‘ltime:‘更新时间‘,id:‘itemId+商品ID‘,‘title:‘商品名称‘,‘name‘:‘设计师名字‘]
            List<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
            List<Item> iList = itemService.listItems();
            for(Item item:iList){
                Designer dir =(Designer)EHUtil.getCache(CacheCode.Cache.code,CacheCode.designer.code+
                        EHUtil.getCache(CacheCode.Cache.code, CacheCode.designerI.code+item.getId()));
                if(dir==null)
                    continue;
                docs.add(ItemHelpService.addDocsHelp(item.getUtime(),"itemId"+item.getId(),item.getName(),
                        dir.getName()));
            }
            SolrUtil.byAddDocs(docs);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Service 主要为数据拉取,可自行编写。

现在索引建立完成,可以开始进行搜索了。

这里需要中文分词器,配合solr的查询功能。方法如下。

ItemHelpService.java

import java.io.IOException;
import java.io.StringReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;

import com.penuel.mythopoetms.model.CacheCode;
import com.penuel.mythopoetms.model.Designer;
import com.penuel.mythopoetms.model.Item;
import com.penuel.mythopoetms.model.SolrCode;
import com.penuel.mythopoetms.utils.EHUtil;
import com.penuel.mythopoetms.utils.SolrUtil;

public class ItemHelpService {

    /**
     * @param date 时间
     * @param strs 多个参数
     * @return
     * @throws ParseException
     */
    public static SolrInputDocument addDocsHelp(Date date,String ...strs) throws ParseException{
        SimpleDateFormat format =  new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); 

        SolrInputDocument doc = new SolrInputDocument();

        doc.addField(SolrCode.ltime.code,date);
        doc.addField(SolrCode.id.code, strs[0]);
        doc.addField(SolrCode.title.code, strs[1]);
        doc.addField(SolrCode.name.code, strs[2]);

        return doc;
    }

    /**
     * @param key  商品名
     * @param key2  设计师
     * @param sort 排序
     * @param start 起始位
     * @param rows 显示页数
     * @return
     */
    public static String[] queryCount(String key,String key2,String sort,int start,int rows){
        ModifiableSolrParams params = new ModifiableSolrParams();

        if(key.equals("*")){
            if(key2.equals(""))
                params.set("q", "*:*");
            else
                params.set("q", "name:"+key2+"*");
        }else{
            if(key.length()<2)
                params.set("q", "title:"+key+"*");
            else
                params.set("q", "title:"+key);

            params.set("fq", toDismantle(key,key2));
        }

        params.set("sort", sort);
        params.set("start", start);
        params.set("rows", rows);

        String [] str = new String[2];
        SolrDocumentList list = SolrUtil.queryPage(params);

        str[0]=SolrUtil.getIds(list);
        str[1]=Long.toString(list.getNumFound());

        return str;
    }

    /**
     * @param text 商品名
     * @param text2 设计师名
     * @return
     */
    public static String[] toDismantle(String text,String text2){
        List<String> list = new ArrayList<String>();
        if(text.length()<2){
            list.add("title:"+text+"*");
        }else{
            StringReader sr=new StringReader(text);
            IKSegmenter ik=new IKSegmenter(sr, true);
            Lexeme lex=null;
            ModifiableSolrParams params = new ModifiableSolrParams();
            params.set("q", "title:"+text);
            try {
                while((lex=ik.next())!=null){
                    list.add("title:"+lex.getLexemeText()+"*");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(StringUtils.isNotBlank(text2)){
            list.add("name:"+text2+"*");
        }
        String[] arr = (String[])list.toArray(new String[list.size()]);
        return arr;
    }
}

这里可能看不太懂,

现讲一下 queryCount方法

key=商品名称,key2=设计师名称,sort=指定字段排序,start=起始位,rows=搜索数量

key默认值为 "*", key2 默认值为 空串即 ""

toDismantle方法

主要针对 key 值 做中文分词(IK2012版本),设计师不需要分词,因为设计师需要单字匹配,但是商品不可以,举一个例子 就会明白

例如,

查询: ("q","title:男士灰色")

不做分词处理的话,数据就会是这样的

输出 "男士灰色XXXX","女士灰色XXXX"

因为 不做分词处理。灰色为同性词,很多不相关的数据会掺杂进来。

做分词处理的效果:

查询: ("q","title:男士灰色")

分词处理并添加条件 ("fq",["title:男士*",title:灰色*])

数据就会过滤掉 不相关的词,比如"女士"等,

还有一处为查询字段长度判断

if(key.length()<2)
      params.set("q", "title:"+key+"*");

如果用户搜索单个词。

例如

查询("q","title:男")

solr的分词器 会自动匹配 "男" 的索引 而不是模糊查询 所以要在后边加上* 来匹配模糊查询。

sort值为排序用,书写规则为 "字段 desc" 或者 "字段 asc"

start,rows。 最常见的分页功能,

start 值为:(当前页- 1) * 显示数量

rows 值为:显示数量

queryCount方法,是一个数组,

[0] 储存的是 查询出来的所有商品ID

[1]储存的是 商品条数

得到这些数据

,使用 sql select *  from A表 where id in (数组[0])  来获取商品列表数据。

然后遍历商品列表,根据其ID值 自动匹配 缓存里存储的 B表 C表 D表 等等数据。

最终效率从最开始的 3秒 到 现在的首次查询仅0.3秒左右,之后,平均查询占0.02秒。

讲到这里基本上是结束了,集体索引的更新操作和缓存操作基本一样,保持缓存 索引和 数据库同步即可。

配置方面可查询之前文章

EH集群:http://www.cnblogs.com/mangyang/p/5481713.html

solr配置:http://www.cnblogs.com/mangyang/p/5500852.html

solr5中文分词:http://www.cnblogs.com/mangyang/p/5502773.html

时间: 2024-07-29 10:03:05

solr5项目实战详解,分布式缓存,全文检索的相关文章

Cocos2d-x手机游戏开发与项目实践详解_随书代码

Cocos2d-x手机游戏开发与项目实战详解_随书代码 作者:沈大海  由于原作者共享的资源为UTF-8字符编码,下载后解压在win下显示乱码或还出现文件不全问题,现完整整理,解决所有乱码问题,供大家下载. 下载地址:http://download.csdn.net/detail/oyangyufu/7665049 Cocos2d-x手机游戏开发与项目实践详解_随书代码

机器学习Spark Mllib算法源码及实战详解进阶与提高视频教程

38套大数据,云计算,架构,数据分析师,Hadoop,Spark,Storm,Kafka,人工智能,机器学习,深度学习,项目实战视频教程 视频课程包含: 38套大数据和人工智能精品高级课包含:大数据,云计算,架构,数据挖掘实战,实时推荐系统实战,电视收视率项目实战,实时流统计项目实战,离线电商分析项目实战,Spark大型项目实战用户分析,智能客户系统项目实战,Linux基础,Hadoop,Spark,Storm,Docker,Mapreduce,Kafka,Flume,OpenStack,Hiv

《iOS 7 应用开发实战详解》

<iOS 7 应用开发实战详解> 基本信息 作者: 朱元波    管蕾 出版社:人民邮电出版社 ISBN:9787115343697 上架时间:2014-4-25 出版日期:2014 年5月 开本:16开 页码:382 版次:1-1 所属分类:计算机 > 软件与程序设计 > 移动开发 > iPhone 更多关于>>><iOS 7 应用开发实战详解> 编辑推荐 新版本 全面讲解了iOS 7开发的各种技术 热门技术 基本控件.数据存储.多场景处理.界

Scala 深入浅出实战经典 第78讲:Type与Class实战详解

王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载: 百度云盘:http://pan.baidu.com/s/1c0noOt6 腾讯微云:http://url.cn/TnGbdC 360云盘:http://yunpan.cn/cQ4c2UALDjSKy 访问密码 45e2土豆:http://www.tudou.com/programs/view/2vZ06RMcD6I/优酷:http://v.youku.com/v_show/id

Scala 深入浅出实战经典 第53讲:Scala中结构类型实战详解

王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 腾讯微云:http://url.cn/TnGbdC 360云盘:http://yunpan.cn/cQ4c2UALDjSKy 访问密码 45e2土豆:http://www.tudou.com/programs/view/pR_4sY0cJLs/优酷:http://v.youku.com/v_show/id_

开源项目MultiChoiceAdapter详解(五)——可扩展的MultiChoiceBaseAdapter

上次写到了开源项目MultiChoiceAdapter详解(四)——MultiChoiceBaseAdapter的使用,其实我们仍旧可以不使用ActionMode的,所以这里就写一个自己扩展的方法. 一.布局文件 listview_normal_layout.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.andr

开源项目MultiChoiceAdapter详解(六)——GridView和MultiChoiceBaseAdapter配合使用

这篇其实没啥重要的,主要就算是个总结吧. 一. 这里实现的是类似于上图的多图选择的效果.关键在于item布局文件的写法.这也就是这个框架奇葩的一点,莫名其妙的要在一个自定义控件里面再放一个自定义的控件,如果不这样就出不了选中的效果.分析下原因是这里整个item被图片所覆盖了,仅仅设置一个有选择效果的父控件会被图片所覆盖,所以还得用一个可以选中的iamgeview进行替换imageview. 下面就是这个布局文件 item_gridview.xml <?xml version="1.0&qu

Dream------scala--类的属性和对象私有字段实战详解

Scala类的属性和对象私有字段实战详解 一.类的属性 scala类的属性跟java有比较大的不同,需要注意的是对象的私有(private)字段 1.私有字段:字段必须初始化(当然即使不是私有字段也要赋值) 2.属性默认是public级别的,而且无法用public修饰. 3.可以有很多类,并且默认是public级别(如果声明的时候加上会报错,不知为何) 4.如果属性是public的,会默认生成类属性的getter和setter方法,无需显示的提供getter,setter方法 5.私有字段(用p

第131讲:Hadoop集群管理工具均衡器Balancer 实战详解学习笔记

第131讲:Hadoop集群管理工具均衡器Balancer 实战详解学习笔记 为什么需要均衡器呢? 随着集群运行,具体hdfs各个数据存储节点上的block可能分布得越来越不均衡,会导致运行作业时降低mapreduce的本地性. 分布式计算中精髓性的一名话:数据不动代码动.降低本地性对性能的影响是致使的,而且不能充分利用集群的资源,因为导致任务计算会集中在部分datanode上,更易导致故障. balancer是hadoop的一个守护进程.会将block从忙的datanode移动到闲的datan