1. 什麼是 Elasticsearchcss
Elastic是一個實時的分佈式搜索分析引擎, 它能讓你以一個以前從未有過的速度和規模,去探索你的數據。 它被用做全文檢索、結構化搜索、分析以及這三個功能的組合。html
下載安裝包 elasticsearch-6.2.4.zip https://www.elastic.co/downloads/elasticsearchjava
解壓壓縮包,其目錄結構以下:node
從命令窗口運行位於bin文件夾中的elasticsearch.bat,可使用CTRL + C中止或關閉它mysql
見到xxxx started,那麼就是啓動完成了,打開瀏覽器輸入http:\\localhost:9200或http:\\127.0.0.1:9200,若是出現如下文本證實啓動成功了。git
{ "name" : "ubH8NDf", "cluster_name" : "elasticsearch", "cluster_uuid" : "sJfrIwlVRBmAArbWRLWyEA", "version" : { "number" : "6.2.4", "build_hash" : "ccec39f", "build_date" : "2018-04-12T20:37:28.497551Z", "build_snapshot" : false, "lucene_version" : "7.2.1", "minimum_wire_compatibility_version" : "5.6.0", "minimum_index_compatibility_version" : "5.0.0" }, "tagline" : "You Know, for Search" }
默認狀況下,Elastic 只容許本機訪問,若是須要遠程訪問,能夠修改 Elastic 安裝目錄的config/elasticsearch.yml文件,去掉network.host的註釋,將它的值改爲0.0.0.0,而後從新啓動 Elastic。github
network.host: 0.0.0.0
sql
上面代碼中,設成0.0.0.0讓任何人均可以訪問。線上服務不要這樣設置,要設成具體的 IP。數據庫
節點1的配置信息: http.cors.enabled: true #是否容許跨域 http.cors.allow-origin: "*" cluster.name: my-esLearn #集羣名稱,保證惟一 node.name: node-1 #節點名稱,必須不同 network.host: 10.118.16.83 #必須爲本機的ip地址 http.port: 9200 #服務端口號,在同一機器下必須不同 transport.tcpport: 9300 #集羣間通訊端口號,在同一機器下必須不同 #設置集羣自動發現機器ip集合 discovery.zen.ping.unicast.hosts: ["10.118.16.83:9300", "10.118.16.83:9301", "10.118.16.83:9302"] 節點2的配置信息: http.cors.enabled: true #是否容許跨域 http.cors.allow-origin: "*" cluster.name: my-esLearn #集羣名稱,保證惟一 node.name: node-2 #節點名稱,必須不同 network.host: 10.118.16.83 #必須爲本機的ip地址 http.port: 9201 #服務端口號,在同一機器下必須不同 transport.tcpport: 9301 #集羣間通訊端口號,在同一機器下必須不同 #設置集羣自動發現機器ip集合 discovery.zen.ping.unicast.hosts: ["10.118.16.83:9300", "10.118.16.83:9301", "10.118.16.83:9302"] 節點3的配置信息: http.cors.enabled: true #是否容許跨域 http.cors.allow-origin: "*" cluster.name: my-esLearn #集羣名稱,保證惟一 node.name: node-3 #節點名稱,必須不同 network.host: 10.118.16.83 #必須爲本機的ip地址 http.port: 9202 #服務端口號,在同一機器下必須不同 transport.tcpport: 9302 #集羣間通訊端口號,在同一機器下必須不同 #設置集羣自動發現機器ip集合 discovery.zen.ping.unicast.hosts: ["10.118.16.83:9300", "10.118.16.83:9301", "10.118.16.83:9302"] `
解壓已經下載 elasticsearch-head-master.zip,同時確認本機已經安裝好nodejs,cmd->node -v確認nodejs是否安全成功。apache
解壓壓縮包,切換到elasticsearch-head-master已解壓好的文件夾下。
c:\elasticsearch-head-master>npm install c:\elasticsearch-head-master>npm start
用瀏覽器打開,http://10.118.16.83:9100/, 只要出現下圖界面就證實成功了。
ES集羣是一個或多個節點的集合,它們共同存儲了整個數據集,並提供了聯合索引以及可跨全部節點的搜索能力。多節點組成的集羣擁有冗餘能力,它能夠在一個或幾個節點出現故障時保證服務的總體可用性。集羣靠其獨有的名稱進行標識,默認名稱爲「elasticsearch」。節點靠其集羣名稱來決定加入哪一個ES集羣,一個節點只能屬一個集羣。
一個節點是一個邏輯上獨立的服務,能夠存儲數據,並參與集羣的索引和搜索功能, 一個節點也有惟一的名字,羣集經過節點名稱進行管理和通訊.
主節點的主要職責是和集羣操做相關的內容,如建立或刪除索引,跟蹤哪些節點是羣集的一部分,並決定哪些分片分配給相關的節點。穩定的主節點對集羣的健康是很是重要的。雖然主節點也能夠協調節點,路由搜索和從客戶端新增數據到數據節點,但最好不要使用這些專用的主節點。一個重要的原則是,儘量作儘可能少的工做。
對於大型的生產集羣來講,推薦使用一個專門的主節點來控制集羣,該節點將不處理任何用戶請求。
持有數據和倒排索引。
它既不能保持數據也不能成爲主節點,該節點能夠響應用戶的狀況,把相關操做發送到其餘節點;客戶端節點會將客戶端請求路由到集羣中合適的分片上。對於讀請求來講,協調節點每次會選擇不一樣的分片處理請求,以實現負載均衡。
ES將數據存儲於一個或多個索引中,索引是具備相似特性的文檔的集合。類比傳統的關係型數據庫領域來講,索引至關於SQL中的一個數據庫,或者一個數據存儲方案(schema)。索引由其名稱(必須爲全小寫字符)進行標識,並經過引用此名稱完成文檔的建立、搜索、更新及刪除操做。一個ES集羣中能夠按需建立任意數目的索引。每一個 Index (即數據庫)的名字必須是小寫。
下面的命令能夠查看當前節點的全部 Index
$ curl -X GET 'http://10.118.16.83:9200/_cat/indices?v'
索引內部的邏輯分區(category/partition),然而其意義徹底取決於用戶需求。所以,一個索引內部可定義一個或多個類型(type)。通常來講,類型就是爲那些擁有相同的域的文檔作的預約義。例如,在索引中,能夠定義一個用於存儲用戶數據的類型,一個存儲日誌數據的類型,以及一個存儲評論數據的類型。類比傳統的關係型數據庫領域來講,類型至關於「表」
Lucene索引和搜索的原子單位,它是包含了一個或多個域的容器,基於JSON格式進行表示。文檔由一個或多個域組成,每一個域擁有一個名字及一個或多個值,有多個值的域一般稱爲「多值域」。每一個文檔能夠存儲不一樣的域集,但同一類型下的文檔至應該有某種程度上的類似之處。至關於數據庫的「記錄」,例如:
{ "user": "張三", "title": "工程師", "desc": "數據庫管理" }
同一個 Index 裏面的 Document,不要求有相同的結構(scheme),可是最好保持相同,這樣有利於提升搜索效率。
至關於數據庫中的schema,用來約束字段的類型,不過 Elastic的 mapping 能夠自動根據數據建立
ES中,全部的文檔在存儲以前都要首先進行分析。用戶可根據須要定義如何將文本分割成token、哪些token應該被過濾掉,以及哪些文本須要進行額外處理等等。
分片(shard) :ES的「分片(shard)」機制可將一個索引內部的數據分佈地存儲於多個節點,它經過將一個索引切分爲多個底層物理的Lucene索引完成索引數據的分割存儲功能,這每個物理的Lucene索引稱爲一個分片(shard)。
每一個分片其內部都是一個全功能且獨立的索引,所以可由集羣中的任何主機存儲。建立索引時,用戶可指定其分片的數量,默認數量爲5個
向指定的 /Index/Type 發送 PUT 請求,就能夠在 Index 裏面新增一條記錄。
$ curl -H "Content-Type:application/json" -X PUT '10.118.16.83:9200/megacorp/employee/1' -d '
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}'
返回:
{ "_index": "megacorp", "_type": "employee", "_id": "1", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 0, "_primary_term": 1 }
若不指定id, 則改成Post請求 。id字段就是一個隨機字符串。
再新增兩條:
$ curl -H "Content-Type:application/json" -X PUT '10.118.16.83:9200/megacorp/employee/2' -d ' { "first_name" : "Jane", "last_name" : "Smith", "age" : 32, "about" : "I like to collect rock albums", "interests": [ "music" ] }' $ curl -H "Content-Type:application/json" -X PUT '10.118.16.83:9200/megacorp/employee/3' -d ' { "first_name" : "Douglas", "last_name" : "Fir", "age" : 35, "about": "I like to build cabinets", "interests": [ "forestry" ] }'
更新記錄就是使用 PUT 請求,從新發送一次數據。
$ curl -H "Content-Type:application/json" -X PUT '10.118.16.83:9200/megacorp/employee/1' -d '
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 26,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}'
返回:
{ "_index": "megacorp", "_type": "employee", "_id": "3", "_version": 2, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 1, "_primary_term": 1 }
記錄的 Id 沒變,可是版本(version)從1變成2,操做類型(result)從created變成updated,created字段變成false,由於此次不是新建記錄
$ curl '10.118.16.83:9200/megacorp/employee/1'
刪除記錄就是發出 DELETE 請求
$ curl -X DELETE '10.118.16.83:9200/megacorp/employee/1'
使用 GET 方法,直接請求/Index/Type/_search,就會返回全部記錄。
$ curl '10.118.16.83:9200/accounts/person/_search' { "took": 4, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 3, "max_score": 1, "hits": [ { "_index": "megacorp", "_type": "employee", "_id": "2", "_score": 1, "_source": { "first_name": "John", "last_name": "Smith", "age": 25, "about": "I love to go rock climbing", "interests": [ "sports", "music" ] } }, …//此處省略 ] } }
上面代碼中,返回結果的 took字段表示該操做的耗時(單位爲毫秒),timed_out字段表示是否超時,hits字段表示命中的記錄,裏面子字段的含義以下。
total:返回記錄數,本例是3條。
max_score:最高的匹配程度,本例是1.0。
hits:返回的記錄組成的數組。
返回的記錄中,每條記錄都有一個_score字段,表示匹配的程序,默認是按照這個字段降序排列。
Elastic提供兩種方式:
l Query-string 搜索經過命令很是方便地進行臨時性的即席搜索 ,但它有自身的侷限性。
$ curl '10.118.16.83:9200/megacorp/employee/_search?q=last_name:Smith'
l 提供一個豐富靈活的查詢語言叫作 查詢表達式 , 它支持構建更加複雜和健壯的查詢。領域特定語言 (DSL), 指定了使用一個 JSON 請求
$ curl -H "Content-Type:application/json" '10.118.16.83:9200/megacorp/employee/_search' -d ' { "query" : { "match" : { "last_name" : " Smith" }} }'
一樣搜索姓氏爲 Smith 的僱員,但此次咱們只須要年齡大於 30 的。查詢須要稍做調整,使用過濾器 filter [range ],它支持高效地執行一個結構化查詢。
$ curl -H "Content-Type:application/json" '10.118.16.83:9200/megacorp/employee/_search' -d '
{
"query" : {
"bool": {
"must": {
"match" : {
"last_name" : "smith"
}
},
"filter": {
"range" : {
"age" : { "gt" : 30 }
}
}
}
}
}'
截止目前的搜索相對都很簡單:單個姓名,經過年齡過濾。如今嘗試下稍微高級點兒的全文搜索——一項 傳統數據庫確實很難搞定的任務。搜索下全部喜歡攀巖(rock climbing)的僱員。
$ curl -H "Content-Type:application/json" '10.118.16.83:9200/megacorp/employee/_search' -d '
{
"query" : {
"match" : {
"about" : "rock climbing"
}
}
}'
獲得兩個匹配的文檔
這是一個很好的案例,闡明瞭 Elasticsearch 如何 在 全文屬性上搜索並返回相關性最強的結果。Elasticsearch中的 相關性 概念很是重要,也是徹底區別於傳統關係型數據庫的一個概念,數據庫中的一條記錄要麼匹配要麼不匹配。
找出一個屬性中的獨立單詞是沒有問題的,但有時候想要精確匹配一系列單詞或者短語 。 好比, 咱們想執行這樣一個查詢,僅匹配同時包含 「rock」 和 「climbing」 ,而且 兩者以短語 「rock climbing」 的形式緊挨着的僱員記錄。
爲此對 match 查詢稍做調整,使用一個叫作 match_phrase 的查詢:
$ curl -H "Content-Type:application/json" '10.118.16.83:9200/megacorp/employee/_search' -d '
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
}
}'
許多應用都傾向於在每一個搜索結果中 高亮 部分文本片斷,以便讓用戶知道爲什麼該文檔符合查詢條件。在 Elasticsearch 中檢索出高亮片斷也很容易。
再次執行前面的查詢,並增長一個新的 highlight 參數:
$ curl -H "Content-Type:application/json" '10.118.16.83:9200/megacorp/employee/_search' -d '
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
},
"highlight": {
"fields" : {
"about" : {}
}
}
}'
查詢結果:
Elasticsearch 有一個功能叫聚合(aggregations),容許咱們基於數據生成一些精細的分析結果。聚合與 SQL 中的 GROUP BY 相似但更強大。
舉個例子,挖掘出僱員中最受歡迎的興趣愛好:
$ curl -H "Content-Type:application/json" '10.118.16.83:9200/megacorp/employee/_search' -d ' { "aggs": { "all_interests": { "terms": { "field": "interests" }, "aggs": { //爲指標新增aggs層 "avg_age": { //指定指標的名字,在返回的結果中也是用這個變量名來儲存數值的 "avg": {//指標參數:平均值 "field": "age" //明確求平均值的字段爲'age' } } } } } }'
執行失敗:
{ "error": { "root_cause": [ { "type": "illegal_argument_exception", "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [interests] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory." } ], "type": "search_phase_execution_exception", "reason": "all shards failed", "phase": "query", "grouped": true, "failed_shards": [ { "shard": 0, "index": "megacorp", "node": "-Md3f007Q3G6HtdnkXoRiA", "reason": { "type": "illegal_argument_exception", "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [interests] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory." } } ], "caused_by": { "type": "illegal_argument_exception", "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [interests] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory." } }, "status": 400 }
排序,聚合這些操做用單獨的數據結構(fielddata)緩存到內存裏了,須要單獨開啓,官方解釋在此fielddata
$ curl -H "Content-Type:application/json" -X POST '10.118.16.83:9200/megacorp/_mapping/employee' -d '
{
"properties":{
"interests":{
"type":"text",
"fielddata":true
}
}
}'
切記,這裏一旦類型錯誤,之後可就麻煩咯
查詢結果:
{"took":40,"timed_out":false,"_shards":{"total":5,"successful":5,"skipped":0,"failed":0},"hits":{"total":4,"max_score":1.0,"hits":[{"_index":"megacorp","_type":"employee","_id":"_cat","_score":1.0,"_source":{ "properties":{ "age":{ "type":"integer", "fielddata":true } } } },{"_index":"megacorp","_type":"employee","_id":"2","_score":1.0,"_source":{ "first_name" : "Jane", "last_name" : "Smith", "age" : 32, "about" : "I like to collect rock albums", "interests": [ "music" ] } },{"_index":"megacorp","_type":"employee","_id":"1","_score":1.0,"_source":{ "first_name" : "John", "last_name" : "Smith", "age" : 25, "about" : "I love to go rock climbing", "interests": [ "sports", "music" ] } },{"_index":"megacorp","_type":"employee","_id":"3","_score":1.0,"_source":{ "first_name" : "Douglas", "last_name" : "Fir", "age" : 35, "about": "I like to build cabinets", "interests": [ "forestry" ] } }]},"aggregations":{"all_interests":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":"music","doc_count":2,"avg_age":{"value":28.5}},{"key":"forestry","doc_count":1,"avg_age":{"value":35.0}},{"key":"sports","doc_count":1,"avg_age":{"value":25.0}}]}}}
Java實現
@Test public void aggsTermsQuery() { SearchResponse response = client.prepareSearch("cars") .setTypes("transactions") .addAggregation(AggregationBuilders.terms("all_interests").field("interests") .subAggregation(AggregationBuilders.avg("avg_price") .field("price"))) .setSize(0) .get(); Map<String, Aggregation> aggMap = response.getAggregations().asMap(); StringTerms teamAgg= (StringTerms) aggMap.get("popular_colors"); Iterator<Bucket> teamBucketIt = teamAgg.getBuckets().iterator(); while (teamBucketIt .hasNext()) { Bucket buck = teamBucketIt .next(); //max/min以此類推 logger.info(buck.getKeyAsString() + ", " + buck.getDocCount()); Map<String, Aggregation> subAggMap = buck.getAggregations().asMap(); long avgAgg= (long) ((InternalAvg)subAggMap.get("avg_price")).getValue(); logger.info("avg:{}", avgAgg); } }
Elastic使用sort進行排序,默認一次返回10條結果,能夠經過size字段改變這個設置。還能夠經過from字段,指定位移。
GET /_search { "query" : { "bool" : { "filter" : { "term" : { "user_id" : 1 }} } }, "sort": { "date": { "order": "desc" }}, "from": 1, "size": 1 }
注意:安裝對應版本的插件。
下載插件https://github.com/medcl/elasticsearch-analysis-ik/releases
要使用 IK Analysis,須要在文檔類裏面,指定相應的分詞器。
ik_max_word 和 ik_smart 區別
ik_max_word: 會將文本作最細粒度的拆分,好比會將「中華人民共和國國歌」拆分爲「中華人民共和國,中華人民,中華,華人,人民共和國,人民,人,民,共和國,共和,和,國國,國歌」,會窮盡各類可能的組合;
ik_smart: 會作最粗粒度的拆分,好比會將「中華人民共和國國歌」拆分爲「中華人民共和國,國歌」。
具體使用可參考https://github.com/medcl/elasticsearch-analysis-ik
public void highlighter() throws UnknownHostException { String preTags = "<strong>"; String postTags = "</strong>"; HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.preTags(preTags);//設置前綴 highlightBuilder.postTags(postTags);//設置後綴 highlightBuilder.field("content"); SearchResponse response = client.prepareSearch("msg") .setTypes("tweet") .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) .setQuery(QueryBuilders.matchQuery("content", "中國")) .highlighter(highlightBuilder) .setFrom(0).setSize(60).setExplain(true) .get(); logger.info("search response is:total=[{}]",response.getHits().getTotalHits()); SearchHits hits = response.getHits(); for (SearchHit hit : hits) { logger.info("{} -- {} -- {}", hit.getId(), hit.getSourceAsString(), hit.getHighlightFields()); } SearchRequestBuilder builder = client.prepareSearch("msg") .setTypes("tweet") .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) .setQuery(QueryBuilders.matchQuery("content", "中國")); }
須要注意的是,咱們經過瀏覽器 http://10.118.16.83:9200 訪問能夠正常訪問,這裏須要知曉,9200端口是用於Http協議訪問的,若是經過客戶端訪問須要經過9300端口才能夠訪問
pom.xml添加依賴
<!-- Elasticsearch核心依賴包 --> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>transport</artifactId> <version>6.2.4</version> </dependency> <!-- 日誌依賴 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.21</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.8.2</version> </dependency>
import java.net.InetAddress; import java.net.UnknownHostException; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.transport.client.PreBuiltTransportClient; import org.junit.Test; public class ElasticsearchTest1 { public static final String HOST = "127.0.0.1"; public static final int PORT = 9200; //http請求的端口是9200,客戶端是9300 @SuppressWarnings("resource") @Test public void test1() throws UnknownHostException { TransportClient client = new PreBuiltTransportClient(Settings.EMPTY).addTransportAddress( new TransportAddress(InetAddress.getByName(HOST), PORT)); System.out.println("Elasticssearch connect info:" + client.toString()); client.close(); } }
import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; import org.elasticsearch.transport.client.PreBuiltTransportClient; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ElasticsearchTest2 { public static final String HOST = "10.118.16.83"; public static final int PORT = 9300; //http請求的端口是9200,客戶端是9300 private TransportClient client = null; private Logger logger = LoggerFactory.getLogger(ElasticsearchTest2.class); public static final String CLUSTER_NAME = "my-esLearn"; //實例名稱 //1.設置集羣名稱:默認是elasticsearch,並設置client.transport.sniff爲true,使客戶端嗅探整個集羣狀態,把集羣中的其餘機器IP加入到客戶端中 private static Settings settings = Settings.builder() .put("cluster.name",CLUSTER_NAME) .put("client.transport.sniff", true) .build(); /** * 獲取客戶端鏈接信息 * @Title: getConnect * @author ld * @date 2018-05-03 * @return void * @throws UnknownHostException */ @SuppressWarnings("resource") @Before public void getConnect() throws UnknownHostException { client = new PreBuiltTransportClient(settings).addTransportAddress( new TransportAddress(InetAddress.getByName(HOST), PORT)); logger.info("鏈接信息:" + client.toString()); } @After public void closeConnect() { if (client != null) { client.close(); } } @Test public void test1() throws UnknownHostException { logger.info("Elasticssearch connect info:" + client.toString()); } @Test public void addIndex() throws IOException { IndexResponse response = client.prepareIndex("msg", "tweet", "2").setSource( XContentFactory.jsonBuilder() .startObject() .field("userName", "es") .field("msg", "Hello,Elasticsearch") .field("age", 14) .endObject()).get(); } @Test public void search() { SearchResponse response = client.prepareSearch("msg") .setTypes("tweet") .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) .setQuery(QueryBuilders.matchPhraseQuery("user_name", "es")) .setFrom(0).setSize(60).setExplain(true) .get(); logger.info("search response is:total=[{}]",response.getHits().getTotalHits()); SearchHits hits = response.getHits(); for (SearchHit hit : hits) { logger.info(hit.getId()); logger.info(hit.getSourceAsString()); } } }
可參考elasticsearch與數據庫同步工具Logstash-input-jdbc
solr |
Elastic |
|
功能 |
官方提供的功能更多 |
官方功能少,可是第三方插件很豐富,擴展能力更強 |
創建索引和查詢效率 |
創建索引的速度和Es差很少,索引創建完成後的檢索速度也很快,可是一邊創建索引一邊搜索會很慢(創建索引時會形成IO阻塞) |
創建索引速度和solr差很少,第一次檢索會比solr慢,以後就快了。一邊創建索引一邊搜索的速度不影響( 索引會先存在內存中,內存不足再寫入磁盤,還有隊列空閒時把索引寫入硬盤) |
支持的數據格式 |
Xml等多種格式 |
json |
分佈式管理 |
zookeeper |
本身維護 |
Sharding |
沒有自動shard rebalancing的功能 |
Shard必須一次設置好,以後不能修改,若是要修改則須要從新創建索引 |
高級查詢 |
沒有Query DSL |
有Query DSL,可以支持更加高級和複雜的查詢語法,並且還能夠以此擴展實現類sql語法的查詢 |
搜索 |
傳統搜索應用 |
實時搜索應用(1s的延遲) |
插件 |
不支持插件式開發 |
支持插件式開發,豐富的插件庫 |