05.SpringDataSolr

SpringDataSolr

Spring Data Solr就是为了方便Solr的开发所研制的一个框架,其底层是对SolrJ(官方API)的封装

一、maven开发环境搭建


SpringDataSolr工程项目结构.png

1). 项目依赖pox.xml

<!-- Spring Data Solr 坐标 -->
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-solr</artifactId>
    <version>1.5.5.RELEASE</version>
</dependency>

<!-- junit -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.9</version>
</dependency>
</dependencies>

<build>
<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
            <encoding>utf-8</encoding>
        </configuration>
    </plugin>
</plugins>
</build>

2). spring容器配置 applicationContext-solr.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:solr="http://www.springframework.org/schema/data/solr"
       xsi:schemaLocation="http://www.springframework.org/schema/data/solr
        http://www.springframework.org/schema/data/solr/spring-solr-1.0.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- solr服务器地址,配置此标签会自动创建 solrServer bean,不需要再手动配置bean -->
    <solr:solr-server id="solrServer" url="http://192.168.74.129:8080/solr" />
    <!--<solr:solr-server id="solrServer" url="http://127.0.0.1:8080/solr" />-->

    <!-- solr模板,使用solr模板可对索引库进行CRUD的操作 -->
    <bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate">
        <constructor-arg ref="solrServer" />
    </bean>
</beans>

3). 文档对应的pojo以及域注解标注

只将于域相关的属性标注出来 【@Field注解 -> 静态/动态域 (复制域没有对应的字段,因为复制域多个静态域的逻辑组成)

package com.lingting;
import org.apache.solr.client.solrj.beans.Field;
import org.springframework.data.solr.core.mapping.Dynamic;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;

public class TbItem implements Serializable {

    /** @Field 注解,配置域 */

    /** 添加一个动态域,专门为动态域设置一个Map集合,让solr根据key创建对应的域
        标识动态域,与solr仓库中配置的动态名一样
     */
    @Dynamic
    @Field("item_spec_*")
    private Map<String, String> specMap;

    /** ~~~ 其他静态域 ~~~ */

    /** 【【【solr 也是根据一个 唯一标识(主键)对一个bean所涉及的域进行增删改查】】】 */
    @Field
    private Long id;

    @Field("item_title")
    private String title;

    @Field("item_image")
    private String image;

    @Field("item_price")
    private BigDecimal price;

    @Field("item_updatetime")
    private Date updateTime;

    @Field("item_goodsid")
    private Long goodsId;

    @Field("item_category")
    private String category;

    @Field("item_brand")
    private String brand;

    @Field("item_seller")
    private String seller;

    /** ~~ 其他字段以及get/set略,需要自行补齐 ~~ */
}

4). 测试类模板 TestTemplate

测试类模板

package com.lingting;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.data.solr.core.SolrTemplate;
import org.springframework.data.solr.core.query.*;
import org.springframework.data.solr.core.query.result.*;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.math.BigDecimal;
import java.util.*;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext-solr.xml")
public class TestTemplate {

    /** 注入 SolrTemplate */
    @Autowired
    private SolrTemplate solrTemplate;

    /** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        下方各个功能模块代码写在此处

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
}

二、SpringDataSolr的基本增删改查

1). 向solr中添加文档

如果设置的 @Field 标识的主键一致,将会将solr中的对应文档进行覆盖

  1. 添加一个文档
/** 向solr中添加一个【文档】 */
@Test
public void addOne() {
    // 创建被 Filed 注解过的bean
    TbItem item = new TbItem();

    // 向 域 对应的字段 设置数据,模拟从数据库中查询
    item.setId(1L);
    item.setTitle("华为P20 Plus 电信5G 32G内存 128G外存 荣耀金");
    item.setImage("http://pic.netbian.com/tupian/23594.html");
    item.setPrice(BigDecimal.valueOf(8000.01));
    item.setUpdateTime(new Date());
    item.setGoodsId(17899888899L);
    item.setCategory("手机");
    item.setBrand("华为");
    item.setGoodsId(1L);
    item.setSeller("华为2号专卖店");

    // 模拟动态域
    Map<String, String> map = new HashMap<>();
    map.put("运行内存", "32G");
    map.put("网络制式", "电信5G");
    item.setSpecMap(map);

    // 向solr中添加 一个文档
    solrTemplate.saveBean(item);

    // 注意,必须得提交!!!!!!!!
    solrTemplate.commit();
    System.out.println("数据插入完成");
}
  1. 添加多个文档
/** 批量插入文档 solrTemplate.saveBeans */
@Test
public void addMany () {
    List<TbItem> list = new ArrayList<>();
    for (int i = 1; i <= 100; i++) {
        TbItem item = new TbItem();
        item.setId(1L + i);
        item.setTitle("华为P" + (20 + i) + " Plus 电信" + (i % 6) + "G " + (32 + i) + "G内存 " + (128 + i) + "G外存 荣耀金");
        item.setImage("http://pic.netbian.com/tupian/23594.html");
        item.setPrice(BigDecimal.valueOf(8000.01 + i));
        item.setUpdateTime(new Date());
        item.setGoodsId(17899888899L + i);
        item.setCategory("手机");
        item.setBrand("华为");
        item.setSeller("华为2号专卖店");

        // 模拟动态域
        Map<String, String> map = new HashMap<>();
        map.put("运行内存", (32 + i) + "G");
        map.put("网络制式", "电信" + (i % 6) + "G");
        item.setSpecMap(map);

        list.add(item);
    }

    // 向solr中添加 一个文档 集合
    solrTemplate.saveBeans(list);
    solrTemplate.commit();
}

2). 向solr中删除文档

  1. 按照主键删除
/** 按照主键删除, 传入一个字符串,solr会自动转换 */
@Test
public void deleteOne() {

    // 删除一个
    solrTemplate.deleteById("1");

    // 删除多个
    List<String> list = new ArrayList<>();
    list.add("2");
    list.add("3");
    list.add("4");
    solrTemplate.deleteById(list);
    solrTemplate.commit();
}
  1. 全部清空
/** 删除全部数据 */
@Test
public void deleteAll () {
    Query query = new SimpleQuery("*:*");
    solrTemplate.delete(query);
    solrTemplate.commit();
}

3). solr中的简单查询

结果打印方法 showList: 打印部分信息

// 显示记录数据
private void showList(ScoredPage<TbItem> page) {
    for (TbItem item : page.getContent()) {
        System.out.println("商品名称:" + item.getTitle() + "  商品价格:" + item.getPrice());
    }

    System.out.println("总记录数:" + page.getTotalElements());
    System.out.println("总页数:" + page.getTotalPages());
}
  1. 按照主键查询
/** 按照 主键查询*/
@Test
public void findOne() {
    TbItem item = solrTemplate.getById(1, TbItem.class);
    System.out.println(item.getTitle());
}
  1. 分页查询
/** 分页查询 */
@Test
public void pageQuery () {
    // 建立查询, 有 查询 表达式: `*:*` 表示查询所有
    Query query = new SimpleQuery("*:*");

    // 开始索引 (默认 0)
    query.setOffset(20);

    // 每页记录数 (默认 10)
    query.setRows(20);

    // 进行查询
    ScoredPage<TbItem> page = solrTemplate.queryForPage(query, TbItem.class);

    // 展示查询的数据内容
    showList(page);
}
  1. 条件查询【重要】
/** 条件查询 */
@Test
public void pageQueryMulti () {
    Query query = new SimpleQuery();

    /* 拼接查询条件,底层封装了表达式
       链式编程,每次调用返回一个新拼接的对象,必须 赋值给原对象,因为返回值是一个新的对象
       拼接条件可以根据需要 查看API; 也可以根据提供的方法进行猜测!
    */
    Criteria criteria = new Criteria("item_title").contains("3");
    criteria = criteria.and("item_price").between(100, 20000);

    query.addCriteria(criteria);

    // 分页查询设置【偏移量】以及【每页数量】
    query.setOffset(1);
    query.setRows(20);

    ScoredPage<TbItem> page = solrTemplate.queryForPage(query, TbItem.class);

    showList(page);
}

三、SpringDataSolr的高级查询方法

不得不吐槽,SpringDataSolr接口设计很繁琐、复杂;一点都不友好;恶心死你!

1). 高亮/条件过滤/排序/分页综合查询

/** 综合案例查询:条件/高亮/分页 查询*/
@Test
public void complexQuery() {

    // 1. 高亮分页查询
    Map searchMap = new HashMap();
    searchMap.put("keywords", "手机");
    searchMap.put("category", "手机");
    searchMap.put("brand", "华为");

    Map specMap = new HashMap();
    specMap.put("网络制式", "电信5G");
    searchMap.put("spec", specMap);

    searchMap.put("price", "8000-*");

    searchMap.put("pageNo", 1);
    searchMap.put("pageSize", 10);
    searchMap.put("sort", "DESC");
    searchMap.put("sortField", "price");

    Map map = searchList(searchMap);

    List<TbItem> list = (List<TbItem>)map.get("rows");
    for (TbItem item : list) {
        System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
        System.out.println(item.getTitle());
        System.out.println(item.getSpecMap());
        System.out.println(item.getPrice());
    }
    System.out.println("总页数: " + map.get("totalPages"));
    System.out.println("总记录数: " + map.get("totalPages"));
}

/** 【很繁琐】按照关键字查询 复制域item_keywords 并 高亮显示 标题域item_title */
private Map searchList (Map searchMap) {

    // 创建结果集容器
    Map map = new HashMap<>();

    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ~~~~~~~~~~~~~~~~~~~~~~ 高亮配置 ~~~~~~~~~~~~~~~~~~~~~
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

    // 1.创建对象高亮查询
    HighlightQuery query = new SimpleHighlightQuery();

    // 设置高亮的域,可能有很多个域。可以通过链式编程添加域
    HighlightOptions highlightOptions = new HighlightOptions().addField("item_title");
    // 高亮前缀
    highlightOptions.setSimplePrefix("<em style='color:red'>");
    // 高亮后缀
    highlightOptions.setSimplePostfix("</em>");
    // 将高亮配置 赋予 给查询对象
    query.setHighlightOptions(highlightOptions);

    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ~~~~~~~~~~~~~~~~~~~~ 配置查询的域 ~~~~~~~~~~~~~~~~~~~~
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

    // 2. 配置查询的域【复制域,有很多的域,包含下方条件/排序的各个域】并将配置赋予给 查询对象
    Criteria criteria = new Criteria("item_keywords").is(searchMap.get("keywords"));
    query.addCriteria(criteria);


    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ~~~~~~~~~~~~~~~ 按照条件进行删选过滤 ~~~~~~~~~~~~~~~~~~~
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

    // 【a.】 根据 分类 进行过滤
    if (!"".equals(searchMap.get("category"))) {

        Criteria filterCriteria =  new Criteria("item_category").is(searchMap.get("category"));
        FilterQuery filterQuery = new SimpleFilterQuery(filterCriteria);
        query.addFilterQuery(filterQuery);
    }

    // 【b.】 根据 品牌 进行过滤
    if (!"".equals(searchMap.get("brand"))) {

        Criteria filterCriteria =  new Criteria("item_brand").is(searchMap.get("brand"));
        FilterQuery filterQuery = new SimpleFilterQuery(filterCriteria);
        query.addFilterQuery(filterQuery);
    }

    // 【c.】 根据 规格 进行过滤, 有多个规格,需要遍历操作!
    if (searchMap.get("spec") != null) {
        Map<String, String> specMap = (Map)(searchMap.get("spec"));

        for (String key : specMap.keySet()) {
            Criteria filterCriteria =  new Criteria("item_spec_" + key).is(specMap.get(key));
            FilterQuery filterQuery = new SimpleFilterQuery(filterCriteria);
            query.addFilterQuery(filterQuery);
        }
    }

    // 【d.】 根据价格进行过滤,尽量让搜索结果多
    if (!"".equals(searchMap.get("price"))) {
        String[] price = ((String)searchMap.get("price")).split("-");
        if (!"0".equals(price[0])) {
            Criteria filterCriteria =  new Criteria("item_price").greaterThan(price[0]);
            FilterQuery filterQuery = new SimpleFilterQuery(filterCriteria);
            query.addFilterQuery(filterQuery);
        }
        if (!"*".equals(price[1])) {
            Criteria filterCriteria =  new Criteria("item_price").lessThan(price[1]);
            FilterQuery filterQuery = new SimpleFilterQuery(filterCriteria);
            query.addFilterQuery(filterQuery);
        }
    }

    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ~~~~~~~~~~~~~~~~~~~~  排序处理  ~~~~~~~~~~~~~~~~~~~~~
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

    // 获取前端传入的排序规则 ASC DESC; 排序的字段【价格/跟新时间...】
    String sortValue = (String) searchMap.get("sort");
    String sortField = (String) searchMap.get("sortField");

    if (sortValue != null && !"".equals(sortValue) && sortField != null && !"".equals(sortField)) {
        if (sortValue.equals("ASC")) {
            // 升序排序, 第一个参数是枚举类型;第二个为被排序的域
            Sort sort = new Sort(Sort.Direction.ASC, "item_" + sortField);
            query.addSort(sort);
        }

        if (sortValue.equals("DESC")) {
            // 升序排序, 第一个参数是枚举类型;第二个为被排序的域
            Sort sort = new Sort(Sort.Direction.DESC, "item_" + sortField);
            query.addSort(sort);
        }
    }

    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ~~~~~~~~~~~~~~~~~~~~  分页处理  ~~~~~~~~~~~~~~~~~~~~~
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

    // 分页查询 需要提高容错性
    // 提取页码
    Integer pageNo = (Integer) searchMap.get("pageNo");
    if (pageNo == null || pageNo <= 0) {
        pageNo = 1;
    }

    // 每页记录数,根据前端排版美观的角度设计
    Integer pageSize = (Integer) searchMap.get("pageSize");
    if (pageSize == null || pageSize <= 0) {
        pageSize = 20;
    }

    // 根据查询的页数与每页显示条数计算开始索引
    query.setOffset((pageNo - 1) * pageSize);
    query.setRows(pageSize);

    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ~~~~~~~~~~~~~~~~~~~~  查询并获取结果  ~~~~~~~~~~~~~~~~~~~~~
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

    // 4. 按照关键字进行查询 获取返回结果
    HighlightPage<TbItem> page = solrTemplate.queryForHighlightPage(query, TbItem.class);

    // 5. 循环【高亮入口】集合,获取每个【文档集合 对应 Items 实体类集合】
    // 注意:page.getContent() 获得的是原始没有高亮的内容
    for (HighlightEntry<TbItem> h : page.getHighlighted()) {

         /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // @@@@ ~:~API设计原理解释及演示~:~ @@@@ 继续上面的步骤!
        // 【Items 实体类集合 】,获取【域集合 -> 字段/属性】
        List<HighlightEntry.Highlight> h2 = h.getHighlights();

        // 遍历【域集合】,比如 复制域 ,与中有多个原始域【Map -> (key:value)】 ,所以需要集合存储!
        for (HighlightEntry.Highlight h3 : h2) {
            List<String> finalResult = h3.getSnipplets();
            System.out.println(finalResult);
        }
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

        // 获取原实体类,将高亮的的域的内容封装到 原实体类中
        // h.getEntity() 与 page.getContent() 获取的是同一个对象!
        TbItem item = h.getEntity();

        // 当前业务逻辑决定了如此判断!
        if (h.getHighlights().size() >0 &&
            h.getHighlights().get(0).getSnipplets().size() > 0) {

            // 设置高亮结果
            item.setTitle(h.getHighlights().get(0).getSnipplets().get(0));
        }
    }

    map.put("rows", page.getContent());
    // 返回总页数
    map.put("totalPages", page.getTotalPages());
    // 返回总记录数
    map.put("total", page.getTotalElements());
    return map;
}

2). 分类查询

根据品牌查询该品牌下的所有商品分类名称

@Test
public void category() {
    Map searchMap = new HashMap();
    searchMap.put("keywords", "华为");
    List<String> list = searchCategoryList(searchMap);
    for (String categoryName : list) {
        System.out.println("~~~~~~~~~~~");
        System.out.println(categoryName);
    }
}


/** 【很繁琐】按照关键字查询 复制域item_keywords 并 根据 分类域item_category 查询 分类列表
 *  */
private List searchCategoryList(Map searchMap) {
    // 创建结果集
    List<String> list = new ArrayList<>();

    // 1、创建查询对象
    Query query = new SimpleQuery();

    // 2、按照关键字进行查询
    Criteria criteria = new Criteria("item_keywords").is(searchMap.get("keywords"));
    query.addCriteria(criteria);

    // 3、设置分组选项;支持链式编程,可以添加 多个分组 的条件,得到多个分组的结果
    GroupOptions groupOptions = new GroupOptions().addGroupByField("item_category");
    query.setGroupOptions(groupOptions);

    // 4、得到查询分组页
    GroupPage<TbItem> page = solrTemplate.queryForGroupPage(query, TbItem.class);

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 复杂设计导致的繁琐 ~~~~~~~~~~~~~~~~~~~~~~~~~~
    // 5~~~、获得指定 分组选项 的结果集,指定的分组条件是 上面第【3、】步中指定的分组条件之一!
    // 注意!((GroupPage<TbItem>)page).getContent() 是空内容,接口设计的不足问题导致的,必须实现的空方法!
    GroupResult<TbItem> groupResult = page.getGroupResult("item_category");

    // 6~~~、得到分组结果入口页
    Page<GroupEntry<TbItem>> groupEntries = groupResult.getGroupEntries();

    // 7~~~、得到分组入口集合
    List<GroupEntry<TbItem>> entryList = groupEntries.getContent();
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    // 8、遍历入口,将分组结果的名称封装到返回值中
    for (GroupEntry<TbItem> entry : entryList) {
        list.add(entry.getGroupValue());
    }

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

推荐阅读更多精彩内容

  • Solr的安装与配置 多数搜索引擎应用都必须具有某种搜索功能,而搜索功能往往大量的消耗资源导致应用程序运行缓慢。为...
    TyCoding阅读 5,255评论 1 5
  • 1. 什么是solr    Solr 是Apache下的一个顶级开源项目,采用Java开发,它是基于Lucene的...
    东方舵手阅读 943评论 1 5
  • 如果你的项目中用到了搜索,现在的选择就奔上就是Solr或者Elasticsearch了,今天我们就来看看Solr,...
    帅可儿妞阅读 671评论 0 1
  • 全文检索技术分析 使用Lucene实现单独使用Lucene实现站内搜索需要开发的工作量较大,主要表现在:索引维护、...
    Zephyr_07阅读 12,634评论 0 5
  • 偶然看到过这样一个故事,说是一个男人的妻子买了一条很漂亮的裙子,想要等到一个很贵重的场合再穿, 可是他的妻子却在一...
    隐栗粑粑罗溪阅读 1,150评论 0 0