SpringBoot整合ElasticSearch實(shí)現(xiàn)多版本的兼容

前言

上一篇學(xué)習(xí)SpringBoot中,整合了Mybatis、Druid和PageHelper并實(shí)現(xiàn)了多數(shù)據(jù)源的操作。本篇主要是介紹和使用目前最火的搜索引擎ElastiSearch揉阎,并和SpringBoot進(jìn)行結(jié)合使用分俯。

ElasticSearch介紹

ElasticSearch是一個(gè)基于Lucene的搜索服務(wù)器,其實(shí)就是對(duì)Lucene進(jìn)行封裝夹抗,提供了 REST API 的操作接口 ElasticSearch作為一個(gè)高度可拓展的開源全文搜索和分析引擎亚铁,可用于快速地對(duì)大數(shù)據(jù)進(jìn)行存儲(chǔ)祸泪,搜索和分析娶眷。
ElasticSearch主要特點(diǎn):分布式偎行、高可用、異步寫入瞳遍、多API闻妓、面向文檔 。
ElasticSearch核心概念:近實(shí)時(shí)掠械,集群,節(jié)點(diǎn)(保存數(shù)據(jù))注祖,索引猾蒂,分片(將索引分片),副本(分片可設(shè)置多個(gè)副本) 是晨。它可以快速地儲(chǔ)存肚菠、搜索和分析海量數(shù)據(jù)。
ElasticSearch使用案例:維基百科罩缴、Stack Overflow蚊逢、Github 等等。

SpringBoot整合Elasticsearch

在使用SpringBoot整合Elasticsearch 之前箫章,我們應(yīng)該了解下它們之間對(duì)應(yīng)版本的關(guān)系烙荷。

Spring Boot Version (x) Spring Data Elasticsearch Version (y) Elasticsearch Version (z)
x <= 1.3.5 y <= 1.3.4 z <= 1.7.2*
x >= 1.4.x 2.0.0 <=y < 5.0.0** 2.0.0 <= z < 5.0.0**

這里我們使用的SpringBoot的版本是1.5.9,Elasticsearch的版本是2.3.5檬寂。

使用SpringBoot整合Elasticsearch终抽,一般都是使用 SpringData 進(jìn)行封裝的,然后再dao層接口繼承ElasticsearchRepository 類,該類實(shí)現(xiàn)了很多的方法昼伴,比如常用的CRUD方法匾旭。

SpringData的使用

首先,在使用之前圃郊,先做好相關(guān)的準(zhǔn)備价涝。

Maven的配置如下:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
             <version>1.5.9.RELEASE</version>
        </dependency>
  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
             <version>1.5.9.RELEASE</version>
        </dependency>

application.properties的配置

spring.data.elasticsearch.repositories.enabled = true
spring.data.elasticsearch.cluster-nodes =127.0.0.1\:9300

注: 9300 是 Java 客戶端的端口。9200 是支持 Restful HTTP 的接口持舆。

更多的配置:

spring.data.elasticsearch.cluster-name Elasticsearch 集群名色瘩。(默認(rèn)值: elasticsearch)
spring.data.elasticsearch.cluster-nodes 集群節(jié)點(diǎn)地址列表,用逗號(hào)分隔吏廉。如果沒有指定泞遗,就啟動(dòng)一個(gè)客戶端節(jié)點(diǎn)。
spring.data.elasticsearch.propertie 用來配置客戶端的額外屬性席覆。
spring.data.elasticsearch.repositories.enabled 開啟 Elasticsearch 倉庫史辙。(默認(rèn)值:true。)

代碼編寫

實(shí)體類

@Document(indexName = "userindex", type = "user")
public class User implements Serializable{
     /**
     * 
     */
    private static final long serialVersionUID = 1L;
    /** 編號(hào) */
     private Long id;
     /** 姓名 */
     private String name;

     /** 年齡 */
     private Integer age;

     /** 描述 */  
     private String description;

     /** 創(chuàng)建時(shí)間 */
     private String createtm;

    // getter和setter 略
}    

使用SpringData的時(shí)候佩伤,它需要在實(shí)體類中設(shè)置indexNametype 聊倔,如果和傳統(tǒng)型數(shù)據(jù)庫比較的話,就相當(dāng)于生巡。需要注意的是indexNametype都必須是小寫!!!

dao層

public interface UserDao extends ElasticsearchRepository<User, Long>{
}

dao層這里就比較簡(jiǎn)單了耙蔑,只需繼承ElasticsearchRepository該類就行了。其中主要的方法就是 save孤荣、delete和search甸陌。其中save方法相當(dāng)如insert和update,沒有就新增盐股,有就覆蓋钱豁。delete方法主要就是刪除數(shù)據(jù)以及索引庫。至于search就是查詢了疯汁,包括一些常用的查詢牲尺,如分頁、權(quán)重之類的幌蚊。

Service層

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;
    @Override
    public boolean insert(User user) {
        boolean falg=false;
        try{
            userDao.save(user);
            falg=true;
        }catch(Exception e){
            e.printStackTrace();
        }
        return falg;
    }

    @Override
    public List<User> search(String searchContent) {
          QueryStringQueryBuilder builder = new QueryStringQueryBuilder(searchContent);
          System.out.println("查詢的語句:"+builder);
          Iterable<User> searchResult = userDao.search(builder);
          Iterator<User> iterator = searchResult.iterator();
          List<User> list=new ArrayList<User>();
          while (iterator.hasNext()) {
            list.add(iterator.next());
          }
       return list;
    }

    @Override
    public List<User> searchUser(Integer pageNumber, Integer pageSize,String searchContent) {
         // 分頁參數(shù)
        Pageable pageable = new PageRequest(pageNumber, pageSize);
        QueryStringQueryBuilder builder = new QueryStringQueryBuilder(searchContent);
        SearchQuery searchQuery = new NativeSearchQueryBuilder().withPageable(pageable).withQuery(builder).build();
        System.out.println("查詢的語句:" + searchQuery.getQuery().toString());
        Page<User> searchPageResults = userDao.search(searchQuery);
        return searchPageResults.getContent();
    }

    @Override
    public List<User> searchUserByWeight(String searchContent) {
     // 根據(jù)權(quán)重進(jìn)行查詢
        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery()
                .add(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("name", searchContent)),
                    ScoreFunctionBuilders.weightFactorFunction(10))
                .add(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("description", searchContent)),
                        ScoreFunctionBuilders.weightFactorFunction(100)).setMinScore(2);
        System.out.println("查詢的語句:" + functionScoreQueryBuilder.toString());
        Iterable<User> searchResult = userDao.search(functionScoreQueryBuilder);
        Iterator<User> iterator = searchResult.iterator();
        List<User> list=new ArrayList<User>();
        while (iterator.hasNext()) {
            list.add(iterator.next());
        }
        return list;
    }
}

這里我就簡(jiǎn)單的寫了幾個(gè)方法谤碳,其中主要的方法是查詢。查詢包括全文搜索溢豆,分頁查詢和權(quán)重查詢蜒简。其中需要說明的是權(quán)重查詢這塊,權(quán)重的分值越高沫换,查詢的結(jié)果也越靠前臭蚁,如果沒有對(duì)其它的數(shù)據(jù)設(shè)置分值最铁,它們默認(rèn)的分值就是1,如果不想查詢這些語句垮兑,只需使用setMinScore將其設(shè)為大于1即可冷尉。

代碼測(cè)試

調(diào)用接口進(jìn)行添加數(shù)據(jù)

新增數(shù)據(jù):

POST http://localhost:8086/api/user

{"id":1,"name":"張三","age":20,"description":"張三是個(gè)Java開發(fā)工程師","createtm":"2018-4-25 11:07:42"}
{"id":2,"name":"李四","age":24,"description":"李四是個(gè)測(cè)試工程師","createtm":"1980-2-15 19:01:32"}
{"id":3,"name":"王五","age":25,"description":"王五是個(gè)運(yùn)維工程師","createtm":"2016-8-21 06:11:32"}

進(jìn)行全文查詢
請(qǐng)求

http://localhost:8086/api/user?searchContent=工程師

返回

[{"id":2,"name":"李四","age":14,"description":"李四是個(gè)測(cè)試工程師","createtm": "1980-2-15 19:01:32"},
{"id":1,"name":"張三","age":20,"description":"張三是個(gè)Java開發(fā)工程師", "createtm": "2018-4-25 11:07:42"},
{"id":3,"name":"王五","age":25,"description":"王五是個(gè)運(yùn)維工程師","createtm": "2016-8-21 06:11:32"}]

進(jìn)行分頁查詢
請(qǐng)求

http://localhost:8086/api/user?pageNumber=0&pageSize=2&searchContent=工程師

返回

[{"id":2,"name":"李四","age":14,"description":"李四是個(gè)測(cè)試工程師"},{"id":1,"name":"張三","age":20,"description":"張三是個(gè)Java開發(fā)工程師"}]

進(jìn)行權(quán)重查詢
請(qǐng)求

http://localhost:8086/api/user2?searchContent=李四

返回

[{"id":2,"name":"李四","age":24,"description":"李四是個(gè)測(cè)試工程師","createtm":"1980-2-15 19:01:32"}]

權(quán)重查詢打印的語句:

查詢的語句:{{
  "function_score" : {
    "functions" : [ {
      "filter" : {
        "bool" : {
          "should" : {
            "match" : {
              "name" : {
                "query" : "李四",
                "type" : "boolean"
              }
            }
          }
        }
      },
      "weight" : 10.0
    }, {
      "filter" : {
        "bool" : {
          "should" : {
            "match" : {
              "description" : {
                "query" : "李四",
                "type" : "boolean"
              }
            }
          }
        }
      },
      "weight" : 100.0
    } ],
    "min_score" : 2.0
  }
}

注:測(cè)試中,因?yàn)樵O(shè)置了setMinScore最小權(quán)重分為2的系枪,所以無關(guān)的數(shù)據(jù)是不會(huì)顯示出來的雀哨。如果想顯示的話,在代碼中去掉即可私爷。

新增完數(shù)據(jù)之后雾棺,可以在瀏覽器輸入:http://localhost:9200/_plugin/head/
然后點(diǎn)擊基本查詢,便可以查看添加的數(shù)據(jù)衬浑。如果想用語句查詢捌浩,可以將程序中控制臺(tái)打印的查詢語句粘貼到查詢界面上進(jìn)行查詢!

image

注:這里的ElasticSearch是我在windows上安裝的,并安裝了ES插件head工秩,具體安裝步驟在文章末尾尸饺。

除了SpringData之外,其實(shí)還有其它的方法操作ElasticSearch的助币。
比如使用原生ElasticSearch的Api浪听,使用TransportClient類實(shí)現(xiàn)。
或者使用由Spring封裝眉菱,只需在Service層迹栓,進(jìn)行注入Bean即可。
示例:

@Autowired
 ElasticsearchTemplate elasticsearchTemplate; 

但是俭缓,上述方法中都有其局限性克伊,也就是隨著ElasticSearch的版本變更,相關(guān)的Java API也在做不斷的調(diào)整华坦,就是ElasticSearch服務(wù)端版本進(jìn)行更改之后答毫,客戶端的代碼可能需要重新編寫。
因此介紹一個(gè)相當(dāng)好用的第三方工具JestClient季春,它對(duì)ElasticSearch進(jìn)行封裝,填補(bǔ)了 ElasticSearch HttpRest接口 客戶端的空白消返,它適用于ElasticSearch2.x以上的版本载弄,無需因?yàn)?strong>ElasticSearch服務(wù)端版本更改而對(duì)代碼進(jìn)行更改!

JestClient

首先在Maven中添加如下依賴:

    <dependency>
        <groupId>io.searchbox</groupId> 
         <artifactId>jest</artifactId>
        <version>5.3.3</version>
    </dependency>

然后編寫相關(guān)的測(cè)試代碼撵颊。
代碼中的注釋應(yīng)該很完整宇攻,所以這里就不再對(duì)代碼過多的講述了。

import java.util.ArrayList;
import java.util.List;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import com.pancm.pojo.User;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestClientFactory;
import io.searchbox.client.JestResult;
import io.searchbox.client.config.HttpClientConfig;
import io.searchbox.core.Bulk;
import io.searchbox.core.BulkResult;
import io.searchbox.core.Delete;
import io.searchbox.core.DocumentResult;
import io.searchbox.core.Index;
import io.searchbox.core.Search;
import io.searchbox.indices.CreateIndex;
import io.searchbox.indices.DeleteIndex;
import io.searchbox.indices.mapping.GetMapping;
import io.searchbox.indices.mapping.PutMapping;

public class JestTest {  
        private static JestClient jestClient;  
        private static String indexName = "userindex";  
//      private static String indexName = "userindex2";  
        private static String typeName = "user";  
        private static String elasticIps="http://192.169.2.98:9200";
//      private static String elasticIps="http://127.0.0.1:9200";

        public static void main(String[] args) throws Exception {
            jestClient = getJestClient();  
            insertBatch();
            serach1();
            serach2();
            serach3();
            jestClient.close();  

        }

        private static  JestClient getJestClient() {  
            JestClientFactory factory = new JestClientFactory();  
            factory.setHttpClientConfig(new HttpClientConfig.Builder(elasticIps).connTimeout(60000).readTimeout(60000).multiThreaded(true).build());  
            return factory.getObject();  
        }  

        public static void insertBatch() {
            List<Object> objs = new ArrayList<Object>();
            objs.add(new User(1L, "張三", 20, "張三是個(gè)Java開發(fā)工程師","2018-4-25 11:07:42"));
            objs.add(new User(2L, "李四", 24, "李四是個(gè)測(cè)試工程師","1980-2-15 19:01:32"));
            objs.add(new User(3L, "王五", 25, "王五是個(gè)運(yùn)維工程師","2016-8-21 06:11:32"));
            boolean result = false;
            try {
                result = insertBatch(jestClient,indexName, typeName,objs);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("批量新增:"+result);
        }

        /**
         * 全文搜索
         */
        public static void serach1() {
            String query ="工程師";
            try {
                SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 
                 searchSourceBuilder.query(QueryBuilders.queryStringQuery(query)); 
                 //分頁設(shè)置
                 searchSourceBuilder.from(0).size(2); 
                System.out.println("全文搜索查詢語句:"+searchSourceBuilder.toString());
                System.out.println("全文搜索返回結(jié)果:"+search(jestClient,indexName, typeName, searchSourceBuilder.toString()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        /**
         * 精確搜索
         */
        public static void serach2() {
            try {
                SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 
                searchSourceBuilder.query(QueryBuilders.termQuery("age", 24)); 
                System.out.println("精確搜索查詢語句:"+searchSourceBuilder.toString());
                System.out.println("精確搜索返回結(jié)果:"+search(jestClient,indexName, typeName, searchSourceBuilder.toString()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        /**
         * 區(qū)間搜索
         */
        public static void serach3() {
            String createtm="createtm";
            String from="2016-8-21 06:11:32";
            String to="2018-8-21 06:11:32";

            try {
                SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 
                searchSourceBuilder.query(QueryBuilders.rangeQuery(createtm).gte(from).lte(to)); 
                System.out.println("區(qū)間搜索語句:"+searchSourceBuilder.toString());
                System.out.println("區(qū)間搜索返回結(jié)果:"+search(jestClient,indexName, typeName, searchSourceBuilder.toString()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        /**
         * 創(chuàng)建索引
         * @param indexName
         * @return
         * @throws Exception
         */
        public boolean createIndex(JestClient jestClient,String indexName) throws Exception {  
            JestResult jr = jestClient.execute(new CreateIndex.Builder(indexName).build());  
            return jr.isSucceeded();  
        }  

        /**
         * 新增數(shù)據(jù)
         * @param indexName
         * @param typeName
         * @param source
         * @return
         * @throws Exception
         */
        public boolean insert(JestClient jestClient,String indexName, String typeName, String source) throws Exception {  
            PutMapping putMapping = new PutMapping.Builder(indexName, typeName, source).build();  
            JestResult jr = jestClient.execute(putMapping);  
            return jr.isSucceeded();  
        }  

         /**
          * 查詢數(shù)據(jù)
          * @param indexName
          * @param typeName
          * @return
          * @throws Exception
          */
        public static String getIndexMapping(JestClient jestClient,String indexName, String typeName) throws Exception {  
            GetMapping getMapping = new GetMapping.Builder().addIndex(indexName).addType(typeName).build();  
            JestResult jr =jestClient.execute(getMapping);  
            return jr.getJsonString();  
         }  

       /**
        * 批量新增數(shù)據(jù)
        * @param indexName
        * @param typeName
        * @param objs
        * @return
        * @throws Exception
        */
        public static boolean insertBatch(JestClient jestClient,String indexName, String typeName, List<Object> objs) throws Exception {  
            Bulk.Builder bulk = new Bulk.Builder().defaultIndex(indexName).defaultType(typeName);  
            for (Object obj : objs) {  
                Index index = new Index.Builder(obj).build();  
                 bulk.addAction(index);  
            }  
            BulkResult br = jestClient.execute(bulk.build());  
            return br.isSucceeded();  
           }  

        /**
         * 全文搜索
         * @param indexName
         * @param typeName
         * @param query
         * @return
         * @throws Exception
         */
        public static String search(JestClient jestClient,String indexName, String typeName, String query) throws Exception {  
             Search search = new Search.Builder(query)
             .addIndex(indexName)
             .addType(typeName)  
             .build(); 
            JestResult jr = jestClient.execute(search);  
//          System.out.println("--"+jr.getJsonString());
//          System.out.println("--"+jr.getSourceAsObject(User.class));
            return jr.getSourceAsString();  
         }  

       /**
        * 刪除索引
        * @param indexName
        * @return
        * @throws Exception
        */
        public boolean delete(JestClient jestClient,String indexName) throws Exception {  
            JestResult jr = jestClient.execute(new DeleteIndex.Builder(indexName).build());  
            return jr.isSucceeded();  
        }  

       /**
        * 刪除數(shù)據(jù)
        * @param indexName
        * @param typeName
        * @param id
        * @return
        * @throws Exception
        */
        public boolean delete(JestClient jestClient,String indexName, String typeName, String id) throws Exception {  
            DocumentResult dr = jestClient.execute(new Delete.Builder(id).index(indexName).type(typeName).build());  
            return dr.isSucceeded();  
        }  

注:測(cè)試之前先說明下倡勇,本地windows系統(tǒng)安裝的是ElasticSearch版本是2.3.5逞刷,linux服務(wù)器上安裝的ElasticSearch版本是6.2。

測(cè)試結(jié)果

全文搜索

全文搜索查詢語句:{
  "from" : 0,
  "size" : 2,
  "query" : {
    "query_string" : {
      "query" : "工程師"
    }
  }
}

全文搜索返回結(jié)果:{"id":1,"name":"張三","age":20,"description":"張三是個(gè)Java開發(fā)工程師","createtm":"2018-4-25 11:07:42"},{"id":2,"name":"李四","age":24,"description":"李四是個(gè)測(cè)試工程師","createtm":"1980-2-15 19:01:32"}

匹配搜索

精確搜索查詢語句:{
  "query" : {
    "term" : {
      "age" : 24
    }
  }
}

精確搜索返回結(jié)果:{"id":2,"name":"李四","age":24,"description":"李四是個(gè)測(cè)試工程師","createtm":"1980-2-15 19:01:32"}

時(shí)間區(qū)間搜索

區(qū)間搜索語句:{
  "query" : {
    "range" : {
      "createtm" : {
        "from" : "2016-8-21 06:11:32",
        "to" : "2018-8-21 06:11:32",
        "include_lower" : true,
        "include_upper" : true
      }
    }
  }
}
區(qū)間搜索返回結(jié)果:{"id":1,"name":"張三","age":20,"description":"張三是個(gè)Java開發(fā)工程師","createtm":"2018-4-25 11:07:42"}

新增完數(shù)據(jù)之后,我們可以上linux的 Kibana中進(jìn)行相關(guān)的查詢夸浅,查詢結(jié)果如下:

image

注:Kibana 是屬于ELK中一個(gè)開源軟件仑最。Kibana可以為 Logstash 和 ElasticSearch 提供的日志分析友好的 Web 界面,可以幫助匯總帆喇、分析和搜索重要數(shù)據(jù)日志警医。

上述代碼中測(cè)試返回的結(jié)果符合我們的預(yù)期。其中關(guān)于JestClient只是用到了很少的一部分坯钦,更多的使用可以查看JestClient的官方文檔预皇。

Windows安裝ElasticSearch

1,文件準(zhǔn)備
下載地址:
https://www.elastic.co/downloads
選擇ElasticSearch相關(guān)版本婉刀, 然后選擇后綴名為ZIP文件進(jìn)行下載吟温,下載之后進(jìn)行解壓。

2突颊,啟動(dòng)Elasticsearch
進(jìn)入bin目錄下鲁豪,運(yùn)行 elasticsearch.bat
然后在瀏覽上輸入: localhost:9200
成功顯示一下界面表示成功!


image

3洋丐,安裝ES插件
web管理界面head 安裝
進(jìn)入bin目錄下呈昔,打開cmd,進(jìn)入dos界面
輸入:plugin install mobz/elasticsearch-head
進(jìn)行下載
成功下載之后友绝,在瀏覽器輸入:http://localhost:9200/_plugin/head/
若顯示一下界面堤尾,則安裝成功!

image

4,注冊(cè)服務(wù)
進(jìn)入bin目錄下迁客,打開cmd郭宝,進(jìn)入dos界面
依次輸入:
service.bat install
service.bat start
成功之后,再輸入
services.msc
跳轉(zhuǎn)到Service服務(wù)界面掷漱,可以直接查看es的運(yùn)行狀態(tài)!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末粘室,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子卜范,更是在濱河造成了極大的恐慌衔统,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件海雪,死亡現(xiàn)場(chǎng)離奇詭異锦爵,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)奥裸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門险掀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人湾宙,你說我怎么就攤上這事樟氢「园恚” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵埠啃,是天一觀的道長(zhǎng)死宣。 經(jīng)常有香客問我,道長(zhǎng)霸妹,這世上最難降的妖魔是什么十电? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮叹螟,結(jié)果婚禮上鹃骂,老公的妹妹穿的比我還像新娘。我一直安慰自己罢绽,他們只是感情好畏线,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著良价,像睡著了一般寝殴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上明垢,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天蚣常,我揣著相機(jī)與錄音,去河邊找鬼痊银。 笑死抵蚊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的溯革。 我是一名探鬼主播贞绳,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼致稀!你這毒婦竟也來了冈闭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤抖单,失蹤者是張志新(化名)和其女友劉穎萎攒,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體矛绘,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡躺酒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蔑歌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡揽碘,死狀恐怖次屠,靈堂內(nèi)的尸體忽然破棺而出园匹,到底是詐尸還是另有隱情,我是刑警寧澤劫灶,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布裸违,位于F島的核電站,受9級(jí)特大地震影響本昏,放射性物質(zhì)發(fā)生泄漏供汛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一涌穆、第九天 我趴在偏房一處隱蔽的房頂上張望怔昨。 院中可真熱鬧,春花似錦宿稀、人聲如沸趁舀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽矮烹。三九已至,卻和暖如春罩锐,著一層夾襖步出監(jiān)牢的瞬間奉狈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國打工涩惑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留仁期,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓境氢,卻偏偏與公主長(zhǎng)得像蟀拷,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子萍聊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容