solr全文檢索學習
序言:
前面我們說了全域性檢索Lucene,但是我們發現Lucene在使用上還是有些不方便的,例如想要看索引的內容時,就必須自己調api去查,再例如一些新增文件,需要寫的程式碼還是比較多的
另外我們之前說過Lucene只是一個全文檢索的工具包,並不算一個完整的搜尋引擎。很多功能還是需要我們自己去完善,去實現的。
solr 和 ElasticSearch 是基於Lucene開發的功能比較完備的全文檢索引擎。
Solr是一個高效能,採用Java開發,基於Lucene的全文搜尋伺服器。同時對其進行了擴充套件,提供了比Lucene更為豐富的查詢語言,同時實現了可配置、可擴充套件並對查詢效能進行了優化,並且提供了一個完善的功能管理介面,是一款非常優秀的全文搜尋引擎。
Solr實際上是一個Web應用,需要servlet容器,可以用Tomcat或者Jetty,新版本Solr預設是用Jetty的,如果要改Tomcat,則要自己做配置。
Solr提供了一些http介面,通過POST請求進行文件的操作,GET請求進行文件的查詢。
要想是用solr,我們就需要先下載 https://lucene.apache.org/solr/
相關文件:https://lucene.apache.org/solr/guide/8_7/getting-started.html
solr目錄說明:
下載後解壓目錄如下
整合Tomcat的你們自己百度,我直接用內建的Jetty
solr服務啟動:
啟動solr時,不要直接雙擊startup.cmd,不然視窗一閃而過,最後還是沒有啟動專案
在命令列裡面執行,啟動後不要關閉命令列,因為預設是後臺程序,關閉命令列後伺服器也會關閉
啟動:solr start [-p 埠 -s home目錄地址]
關閉:直接關閉命令列,或者,solr stop -all 關閉全部,或者,solr stop -p 8983 只關閉8983埠的伺服器
重啟:solr restart -p 埠
幫助:solr --help ,或者,solr start -help
啟動完後直接瀏覽器訪問 http://localhost:8983/
一般來說solr的管理後臺介面是不需要認證的,但是我們不可能讓所有人都可以訪問,所以我們需要修改認證
Jetty伺服器啟動認證:
首先在解壓包的 /server/etc 目錄中隨便建個properties檔案,檔名隨意,填入使用者密碼角色
然後在 /server/contexts 目錄中的 solr-jetty-context.xml 複製那段程式碼,檔名要和剛剛你建的檔名一致
<Get name="securityHandler"> <Set name="loginService"> <New class="org.eclipse.jetty.security.HashLoginService"> <Set name="name">verify—name</Set> <Set name="config"> <SystemProperty name="jetty.home" default="." />/etc/verify.properties </Set> </New> </Set> </Get>
接著去 \server\solr-webapp\webapp\WEB-INF 目錄中的 web.xml檔案中註釋掉選中的程式碼
緊接著加上一段程式碼,指定資源認證
<security-constraint> <web-resource-collection> <web-resource-name>Solr</web-resource-name> <url-pattern>/*</url-pattern> <http-method>GET</http-method> <http-method>DELETE</http-method> <http-method>POST</http-method> <http-method>PUT</http-method> </web-resource-collection> <auth-constraint> <role-name>admin</role-name> <role-name>user</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> <realm-name>verify-name</realm-name> </login-config>
效果:
相關參考部落格:
https://blog.csdn.net/u011561335/article/details/90695860
https://www.cnblogs.com/w1995w/p/10566218.html
整合Tomcat時開啟認證:
https://www.cnblogs.com/anny0404/p/5570666.html
solr的管理介面功能:
Dashboard:
儀表盤,顯示了該Solr例項開始啟動執行的時間、版本、系統資源、jvm等資訊
Logging:
日誌資訊,還可以修改記錄的日誌級別
Core :
core核心管理,類似與MySQL裡面表的概念
注意,新建一個core核心,不能簡單的在頁面上操作就行,需要在本地磁碟新增一些配置檔案,否則就會報錯。
首先你要去你的solr的home目錄建一個資料夾,取名隨意,建議和新core的名字一致
緊接著去 \server\solr\configsets\_default 目錄裡面複製conf這個資料夾,裡面有必須的配置檔案
回到我們剛剛新建的目錄,貼上下去,重啟solr
點選add core,然後重新整理頁面,就出現新的了
java properties
Solr在JVM 執行環境中的屬性資訊,包括類路徑、檔案編碼、jvm記憶體設定等資訊。
Tread Dump:
顯示Solr Server中當前活躍執行緒資訊,同時也可以跟蹤執行緒執行棧資訊。
Core selector
選擇一個SolrCore進行詳細操作
Overview:
概況
analysis:
通過此介面可以測試索引分析器和搜尋分析器的執行情況
Dataimport:
可以定義資料匯入處理器,從關係資料庫將資料匯入 到Solr索引庫中。
Documents:
通過此選單可以建立索引、更新索引、刪除索引等操作
/update表示更新索引,solr預設根據id(唯一約束)域來更新Document的內容,如果根據id值搜尋不到id域則會執行新增操作,如果找到則更新
Files:
Plugins:
Query:
可以進行各種查詢
Replication :
Schema:
配置ik分詞器:
solr的管理介面基本就這樣了
下面我們配置以下ik分詞器
配置上和之前我們弄Lucene是一樣的,這是官網地址 https://github.com/magese/ik-analyzer-solr
下載jar包放到 /WEB-INF/lib 資料夾中
複製幾個配置檔案和詞典到classes資料夾中
如果要用那幾個詞典的話,要自己加上
去你要使用ik分詞器的core的約束檔案上進行修改
加入以下這一段話
<fieldType name="text_ik" class="solr.TextField"> <analyzer type="index"> <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" conf="ik.conf" useSmart="false"/> <filter class="solr.LowerCaseFilterFactory"/> </analyzer> <analyzer type="query"> <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" conf="ik.conf" useSmart="true"/> <filter class="solr.LowerCaseFilterFactory"/> </analyzer> </fieldType>
接下來你就可以自己給Field指定ik分詞器了
同時頁面也會顯示ik分詞器了
不過需要注意的是,那個core需要用ik分詞器,那個core就需要配置,無法全域性配置
solr配置檔案:
有幾個配置檔案我們會經常用到,所以有必要了解下:
core.properties:
裡面存放了核心的名字
solrconfig.xml:
這個類其實主要就是配置一些handler,下面是精簡後的一些程式碼,像
/query
/update 這樣的處理介面,也是在這裡進行配置的,包括我們後期需要加的匯入功能,也是要在這裡加一個handler
<?xml version="1.0" encoding="UTF-8" ?> <luceneMatchVersion>8.7.0</luceneMatchVersion> <dataDir>${solr.data.dir:}</dataDir> <directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.NRTCachingDirectoryFactory}" /> <codecFactory class="solr.SchemaCodecFactory" /> <indexConfig> <lockType>${solr.lock.type:native}</lockType> </indexConfig> <jmx /> <updateHandler class="solr.DirectUpdateHandler2"> <updateLog> <str name="dir">${solr.ulog.dir:}</str> <int name="numVersionBuckets">${solr.ulog.numVersionBuckets:65536}</int> </updateLog> <autoCommit> <maxTime>${solr.autoCommit.maxTime:15000}</maxTime> <openSearcher>false</openSearcher> </autoCommit> <autoSoftCommit> <maxTime>${solr.autoSoftCommit.maxTime:-1}</maxTime> </autoSoftCommit> </updateHandler> <query> <maxBooleanClauses>${solr.max.booleanClauses:1024}</maxBooleanClauses> <filterCache class="solr.FastLRUCache" size="512" initialSize="512" autowarmCount="0" /> <queryResultCache class="solr.LRUCache" size="512" initialSize="512" autowarmCount="0" /> <documentCache class="solr.LRUCache" size="512" initialSize="512" autowarmCount="0" /> <cache name="perSegFilter" class="solr.search.LRUCache" size="10" initialSize="0" autowarmCount="10" regenerator="solr.NoOpRegenerator" /> <enableLazyFieldLoading>true</enableLazyFieldLoading> <queryResultWindowSize>20</queryResultWindowSize> <queryResultMaxDocsCached>200</queryResultMaxDocsCached> <listener event="newSearcher" class="solr.QuerySenderListener"> <arr name="queries"> </arr> </listener> <listener event="firstSearcher" class="solr.QuerySenderListener"> <arr name="queries"> </arr> </listener> <useColdSearcher>false</useColdSearcher> </query> <circuitBreakers enabled="true"> </circuitBreakers> <requestDispatcher> <httpCaching never304="true" /> </requestDispatcher> <requestHandler name="/select" class="solr.SearchHandler"> <lst name="defaults"> <str name="echoParams">explicit</str> <int name="rows">10</int> </lst> </requestHandler> <requestHandler name="/query" class="solr.SearchHandler"> <lst name="defaults"> <str name="echoParams">explicit</str> <str name="wt">json</str> <str name="indent">true</str> </lst> </requestHandler> <initParams path="/update/**,/query,/select,/spell"> <lst name="defaults"> <str name="df">_text_</str> </lst> </initParams> <searchComponent name="spellcheck" class="solr.SpellCheckComponent"> <str name="queryAnalyzerFieldType">text_general</str> <lst name="spellchecker"> <str name="name">default</str> <str name="field">_text_</str> <str name="classname">solr.DirectSolrSpellChecker</str> <str name="distanceMeasure">internal</str> <float name="accuracy">0.5</float> <int name="maxEdits">2</int> <int name="minPrefix">1</int> <int name="maxInspections">5</int> <int name="minQueryLength">4</int> <float name="maxQueryFrequency">0.01</float> </lst> </searchComponent> <requestHandler name="/spell" class="solr.SearchHandler" startup="lazy"> <lst name="defaults"> <str name="spellcheck.dictionary">default</str> <str name="spellcheck">on</str> <str name="spellcheck.extendedResults">true</str> <str name="spellcheck.count">10</str> <str name="spellcheck.alternativeTermCount">5</str> <str name="spellcheck.maxResultsForSuggest">5</str> <str name="spellcheck.collate">true</str> <str name="spellcheck.collateExtendedResults">true</str> <str name="spellcheck.maxCollationTries">10</str> <str name="spellcheck.maxCollations">5</str> </lst> <arr name="last-components"> <str>spellcheck</str> </arr> </requestHandler> <searchComponent name="terms" class="solr.TermsComponent" /> <requestHandler name="/terms" class="solr.SearchHandler" startup="lazy"> <lst name="defaults"> <bool name="terms">true</bool> <bool name="distrib">false</bool> </lst> <arr name="components"> <str>terms</str> </arr> </requestHandler> <searchComponent class="solr.HighlightComponent" name="highlight"> <highlighting> <fragmenter name="gap" default="true" class="solr.highlight.GapFragmenter"> <lst name="defaults"> <int name="hl.fragsize">100</int> </lst> </fragmenter> <fragmenter name="regex" class="solr.highlight.RegexFragmenter"> <lst name="defaults"> <int name="hl.fragsize">70</int> <float name="hl.regex.slop">0.5</float> <str name="hl.regex.pattern">[-\w ,/\n\"']{20,200}</str> </lst> </fragmenter> <formatter name="html" default="true" class="solr.highlight.HtmlFormatter"> <lst name="defaults"> <str name="hl.simple.pre"> <![CDATA[<em>]]> </str> <str name="hl.simple.post"> <![CDATA[</em>]]> </str> </lst> </formatter> <encoder name="html" class="solr.highlight.HtmlEncoder" /> <fragListBuilder name="simple" class="solr.highlight.SimpleFragListBuilder" /> <fragListBuilder name="single" class="solr.highlight.SingleFragListBuilder" /> <fragListBuilder name="weighted" default="true" class="solr.highlight.WeightedFragListBuilder" /> <fragmentsBuilder name="default" default="true" class="solr.highlight.ScoreOrderFragmentsBuilder"> </fragmentsBuilder> <fragmentsBuilder name="colored" class="solr.highlight.ScoreOrderFragmentsBuilder"> <lst name="defaults"> <str name="hl.tag.pre"> <![CDATA[ <b style="background:yellow">,<b style="background:lawgreen">, <b style="background:aquamarine">,<b style="background:magenta">, <b style="background:palegreen">,<b style="background:coral">, <b style="background:wheat">,<b style="background:khaki">, <b style="background:lime">,<b style="background:deepskyblue">]]> </str> <str name="hl.tag.post"> <![CDATA[</b>]]> </str> </lst> </fragmentsBuilder> <boundaryScanner name="default" default="true" class="solr.highlight.SimpleBoundaryScanner"> <lst name="defaults"> <str name="hl.bs.maxScan">10</str> <str name="hl.bs.chars">.,!? 	 </str> </lst> </boundaryScanner> <boundaryScanner name="breakIterator" class="solr.highlight.BreakIteratorBoundaryScanner"> <lst name="defaults"> <str name="hl.bs.type">WORD</str> <str name="hl.bs.language">en</str> <str name="hl.bs.country">US</str> </lst> </boundaryScanner> </highlighting> </searchComponent> <updateProcessor class="solr.UUIDUpdateProcessorFactory" name="uuid" /> <updateProcessor class="solr.RemoveBlankFieldUpdateProcessorFactory" name="remove-blank" /> <updateProcessor class="solr.FieldNameMutatingUpdateProcessorFactory" name="field-name-mutating"> <str name="pattern">[^\w-\.]</str> <str name="replacement">_</str> </updateProcessor> <updateProcessor class="solr.ParseBooleanFieldUpdateProcessorFactory" name="parse-boolean" /> <updateProcessor class="solr.ParseLongFieldUpdateProcessorFactory" name="parse-long" /> <updateProcessor class="solr.ParseDoubleFieldUpdateProcessorFactory" name="parse-double" /> <updateProcessor class="solr.ParseDateFieldUpdateProcessorFactory" name="parse-date"> <arr name="format"> <str>yyyy-MM-dd['T'[HH:mm[:ss[.SSS]][z</str> <str>yyyy-MM-dd['T'[HH:mm[:ss[,SSS]][z</str> <str>yyyy-MM-dd HH:mm[:ss[.SSS]][z</str> <str>yyyy-MM-dd HH:mm[:ss[,SSS]][z</str> <str>[EEE, ]dd MMM yyyy HH:mm[:ss] z</str> <str>EEEE, dd-MMM-yy HH:mm:ss z</str> <str>EEE MMM ppd HH:mm:ss [z ]yyyy</str> </arr> </updateProcessor> <updateProcessor class="solr.AddSchemaFieldsUpdateProcessorFactory" name="add-schema-fields"> <lst name="typeMapping"> <str name="valueClass">java.lang.String</str> <str name="fieldType">text_general</str> <lst name="copyField"> <str name="dest">*_str</str> <int name="maxChars">256</int> </lst> <bool name="default">true</bool> </lst> <lst name="typeMapping"> <str name="valueClass">java.lang.Boolean</str> <str name="fieldType">booleans</str> </lst> <lst name="typeMapping"> <str name="valueClass">java.util.Date</str> <str name="fieldType">pdates</str> </lst> <lst name="typeMapping"> <str name="valueClass">java.lang.Long</str> <str name="valueClass">java.lang.Integer</str> <str name="fieldType">plongs</str> </lst> <lst name="typeMapping"> <str name="valueClass">java.lang.Number</str> <str name="fieldType">pdoubles</str> </lst> </updateProcessor> <updateRequestProcessorChain name="add-unknown-fields-to-the-schema" default="${update.autoCreateFields:true}" processor="uuid,remove-blank,field-name-mutating,parse-boolean,parse-long,parse-double,parse-date,add-schema-fields"> <processor class="solr.LogUpdateProcessorFactory" /> <processor class="solr.DistributedUpdateProcessorFactory" /> <processor class="solr.RunUpdateProcessorFactory" /> </updateRequestProcessorChain> <queryResponseWriter name="json" class="solr.JSONResponseWriter"> <str name="content-type">text/plain; charset=UTF-8</str> </queryResponseWriter> <requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler"> <lst name="defaults"> <str name="config">data-config.xml</str> </lst> </requestHandler> </config>
managed-schema:
這是一個約束檔案,用於指定有哪些Field,Field是否索引、是否分析、是否存在、是否多值,用了哪些分詞器
uniqueKey:指定一個field為主鍵,Lucene中為我們弄了個自增的id作為主鍵,但是solr選擇將id放給我們自己決定。新增文件時必須指定id
fieldType:field型別,可以指定具體是用哪個類處理,是否使用分詞器
field:定義一個field,相當於以前Lucene程式碼的 Field fileNameField = new TextField("file_name",fileName, Field.Store.YES);
dynamicField:可以使用萬用字元,當我們不確定field名字時,就可以用動態Field
copyField:拷貝Field,將多個field的值整合在一個新的field中,並對新的field進行索引,dest屬性指定的目標field必須要是多值的,否則會報錯
假設我們有這樣的一個配置,title和name的值都會拷貝一份到content_text中 <field name="my_name" type="text_ik" indexed="true" stored="true"/> <field name="my_title" type="text_ik" indexed="true" stored="true"/> <field name="my_content_text" type="text_ik" indexed="true" stored="true" multiValued="true"/> <copyField source="my_name" dest="my_content_text" /> <copyField source="my_title" dest="my_content_text" /> 此時我插入一條文件 { "id":"1", "my_name":"張三", "my_title":"法外狂徒" } 那他實際最後會插入成 { "id":"1", "my_name":"張三", "my_title":"法外狂徒", "my_content_text":["張三", "法外狂徒"], }
solr將以前Lucene的程式碼實現,改成了配置檔案的形式
從資料庫匯入:
正常來說,沒進行過任何配置的話,是沒法使用匯入功能的
所以我們需要進行一些配置。
首先我們要找到這兩個jar包
把他們複製到 \webapp\WEB-INF\lib 這裡面。然後根據你要操作的資料庫,匯入對應的jdbc包,我用的是mysql
我有一堆資料
到你要配置匯入的core的配置資料夾中,建立一個data-config.xml檔案,檔名隨意
<?xml version="1.0" encoding="UTF-8" ?> <dataConfig> <dataSource type="JdbcDataSource" driver="com.mysql.cj.jdbc.Driver" url="jdbc:mysql://localhost:3306/sys?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8" user="root" password="root"/> <document> <entity name="product" query="SELECT pid,name,catalog_name,price,description,picture FROM products "> <field column="pid" name="id"/> <field column="name" name="product_name"/> <field column="catalog_name" name="product_catalog_name"/> <field column="price" name="product_price"/> <field column="description" name="product_description"/> <field column="picture" name="product_picture"/> </entity> </document> </dataConfig>
然後修改solrconfig.xml,新增上匯入的handler
<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler"> <lst name="defaults"> <str name="config">data-config.xml</str> </lst> </requestHandler>
完了後就重啟solr就可以用了
匯入的可以參考官網這個文件:https://lucene.apache.org/solr/guide/8_7/uploading-structured-data-store-data-with-the-data-import-handler.html
管理介面增刪改查:
客戶端增刪改查:
有兩個客戶端,solrJ 和 Spring Data Solr ,下面我們兩個都會講到
solrJ :
先加依賴:
<!-- solrJ客戶端 --> <dependency> <groupId>org.apache.solr</groupId> <artifactId>solr-solrj</artifactId> <version>8.7.0</version> </dependency> <!-- 編解碼的依賴,如果solr沒有開認證,可以不加 --> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.14</version> </dependency>
因為我自己solr開啟了認證,所以url地址要加上使用者名稱和密碼
private final static String solrUrl = "http://root:[email protected]:8983/solr/new_core";
而且還要自己額外手動建立一個HttpClient
SystemDefaultHttpClient httpclient = new SystemDefaultHttpClient();
目前新版本中solr伺服器加密碼後,solrJ我只找到這樣連結,如果還有別的方法,請留意告訴我一下,謝謝
package com.hongcheng.solrJ; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.client.SystemDefaultHttpClient; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.beans.Field; import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.client.solrj.impl.HttpSolrClient; import org.apache.solr.client.solrj.response.QueryResponse; 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 org.apache.solr.common.params.MultiMapSolrParams; import org.apache.solr.common.params.SolrParams; import org.junit.jupiter.api.Test; import org.springframework.util.IdGenerator; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Random; import java.util.UUID; class SolrJDemoTest { private final static String solrUrl = "http://root:[email protected]:8983/solr/new_core"; /** * 新增文件 * 第1步:和Solr伺服器建立連線。HttpSolrClient物件建立連線。 * 第2步:建立一個SolrInputDocument物件,然後新增域。 * 第3步:將SolrInputDocument新增到索引庫。 * 第4步:提交。 * */ @Test public void addDocument() throws IOException, SolrServerException { SystemDefaultHttpClient httpclient = new SystemDefaultHttpClient(); // 第1步:和Solr伺服器建立連線。HttpSolrClient物件建立連線。 HttpSolrClient solrClient = new HttpSolrClient.Builder() .withBaseSolrUrl(solrUrl) .withHttpClient(httpclient) .build(); // 第2步:建立一個SolrInputDocument物件,然後新增域。 SolrInputDocument document = new SolrInputDocument(); document.addField("id", UUID.randomUUID().toString().replace("-","")); document.addField("my_name","老鐵"); document.addField("my_title","666"); System.err.println(solrClient.getInvariantParams()); solrClient.add(document); solrClient.commit(); solrClient.close(); } /** * 把一個javabean新增進去 * */ @Test public void addDocumentBean() throws IOException, SolrServerException { SystemDefaultHttpClient httpclient = new SystemDefaultHttpClient(); // 第1步:和Solr伺服器建立連線。HttpSolrClient物件建立連線。 HttpSolrClient solrClient = new HttpSolrClient.Builder() .withBaseSolrUrl(solrUrl) .withHttpClient(httpclient) .build(); solrClient.addBean(new User(UUID.randomUUID().toString().replace("-",""),"李四","群中惡霸")); solrClient.commit(); solrClient.close(); } /** * 更新 * 其實並沒有實際的更新方法,都是通過add方法新增,如果id值已經存在,就刪除再新增 * */ @Test public void updataDocument() throws IOException, SolrServerException { SystemDefaultHttpClient httpclient = new SystemDefaultHttpClient(); // 第1步:和Solr伺服器建立連線。HttpSolrClient物件建立連線。 HttpSolrClient solrClient = new HttpSolrClient.Builder() .withBaseSolrUrl(solrUrl) .withHttpClient(httpclient) .build(); solrClient.addBean(new User("e2d1cdb08857452ebd13a460d49e067f","李四","李四不是群中惡霸")); solrClient.commit(); solrClient.close(); } /** * 刪除 * */ @Test public void daleteDocument() throws IOException, SolrServerException { SystemDefaultHttpClient httpclient = new SystemDefaultHttpClient(); // 第1步:和Solr伺服器建立連線。HttpSolrClient物件建立連線。 HttpSolrClient solrClient = new HttpSolrClient.Builder() .withBaseSolrUrl(solrUrl) .withHttpClient(httpclient) .build(); solrClient.addBean(new User("e2d1cdb08857452ebd13a460d49e067f","李四","李四不是群中惡霸")); solrClient.commit(); solrClient.close(); } /** * 刪除 * */ @Test public void searchDocument() throws IOException, SolrServerException { SystemDefaultHttpClient httpclient = new SystemDefaultHttpClient(); // 第1步:和Solr伺服器建立連線。HttpSolrClient物件建立連線。 HttpSolrClient solrClient = new HttpSolrClient.Builder() .withBaseSolrUrl(solrUrl) .withHttpClient(httpclient) .build(); //建立一個query物件 SolrQuery query = new SolrQuery(); //設定查詢條件,q是必須要填的,如果不填,會查不出來 query.setQuery("*:*"); //過濾條件, query.setFilterQueries("product_catalog_name:幽默雜貨"); //排序條件 query.setSort("product_price", SolrQuery.ORDER.asc); //分頁處理 query.setStart(0); query.setRows(10); query.setFields("id","product_name","product_price","product_catalog_name","product_description"); //設定預設搜尋域 // query.set("df", "product_keywords"); //高亮顯示 query.setHighlight(true); //高亮顯示的域 query.addHighlightField("product_name"); //高亮顯示的字首 query.setHighlightSimplePre("<span stype='color:red;'>"); //高亮顯示的字尾 query.setHighlightSimplePost("</span>"); System.err.println(query); //執行查詢 QueryResponse queryResponse = solrClient.query(query); //取查詢結果 SolrDocumentList solrDocumentList = queryResponse.getResults(); //共查詢到商品數量 System.out.println("共查詢到商品數量:" + solrDocumentList.getNumFound()); //遍歷查詢的結果 for (SolrDocument solrDocument : solrDocumentList) { System.out.println(solrDocument.get("id")); //取高亮顯示 String productName = ""; Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting(); List<String> list = highlighting.get(solrDocument.get("id")).get("product_name"); //判斷是否有高亮內容 if (null != list) { productName = list.get(0); } else { productName = (String) solrDocument.get("product_name"); } System.out.println(productName); System.out.println(solrDocument.get("product_price")); System.out.println(solrDocument.get("product_catalog_name")); System.out.println(solrDocument.get("product_picture")); } solrClient.close(); } } @Getter @Setter @AllArgsConstructor class User{ @Field("id") private String id; @Field("my_name") private String name; @Field("my_title") private String title; }
Spring Data Solr:
依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-solr</artifactId> </dependency>
配置檔案:
這兩個是我們自己的自定義屬性
spring: data: solr: host: http://root:[email protected]:8983/solr #因為我自己solr服務開啟了認證,所以這裡我要加上使用者名稱和密碼 core: new_core
配置檔案:
注入bean
package com.hongcheng.solrJ; import org.apache.http.impl.client.SystemDefaultHttpClient; import org.apache.solr.client.solrj.impl.HttpSolrClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.solr.core.SolrTemplate; @Configuration public class SolrConfig { @Value("${spring.data.solr.host}") private String solrHost; @Value("${spring.data.solr.core}") private String solrCore; /** * 配置SolrTemplate */ @Bean public SolrTemplate solrTemplate() { SystemDefaultHttpClient httpclient = new SystemDefaultHttpClient(); // 第1步:和Solr伺服器建立連線。HttpSolrClient物件建立連線。 HttpSolrClient solrClient = new HttpSolrClient.Builder() .withBaseSolrUrl(solrHost) .withHttpClient(httpclient) .build(); SolrTemplate template = new SolrTemplate(solrClient); return template; } }
增刪改查程式碼:
package com.hongcheng.springdatasolr; import com.hongcheng.solrJ.SolrConfig; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import lombok.ToString; import org.apache.solr.client.solrj.beans.Field; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; 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.HighlightEntry; import org.springframework.data.solr.core.query.result.HighlightPage; import javax.annotation.Resource; import java.util.List; import java.util.Optional; import java.util.UUID; @SpringBootTest(classes = SolrConfig.class) public class SpringDataSolrDemoTest { @Resource private SolrTemplate solrTemplate; /** * 新增文件 * */ @Test public void addDocument(){ solrTemplate.saveBean("new_core",new SpringDataSolrDemoTest.User(UUID.randomUUID().toString().replace("-",""),"李四","群中惡霸2222")); solrTemplate.commit("new_core"); } /** * 根據id更新文件 * */ @Test public void updateDocument(){ solrTemplate.saveBean("new_core",new SpringDataSolrDemoTest.User("d0e5d628b5724c9ab3d903ba1b88d683","李四","群中惡霸3333")); solrTemplate.commit("new_core"); } /** * 根據id刪除文件 * */ @Test public void deleteDocumentById(){ solrTemplate.deleteByIds("new_core","d0e5d628b5724c9ab3d903ba1b88d683"); solrTemplate.commit("new_core"); } /** * 條件刪除文件 * */ @Test public void deleteDocumentByQuery(){ SolrDataQuery solrDataQuery = new SimpleQuery(); solrDataQuery.addCriteria(new Criteria("my_title").is("惡霸")); solrTemplate.delete("new_core",solrDataQuery); solrTemplate.commit("new_core"); } /** * 根據id查詢文件 * */ @Test public void searchById(){ Optional<Product> new_core = solrTemplate.getById("new_core", "4701", Product.class); System.err.println(new_core.get()); solrTemplate.commit("new_core"); } /** * 條件查詢文件 * */ @Test public void searchByQuery(){ SimpleHighlightQuery simpleHighlightQuery = new SimpleHighlightQuery(); // 分頁 simpleHighlightQuery.setPageRequest( PageRequest.of(0,10, Sort.Direction.ASC,"product_price")); // 設定投影 simpleHighlightQuery.addProjectionOnField("id"); simpleHighlightQuery.addProjectionOnField("product_catalog_name"); simpleHighlightQuery.addProjectionOnField("product_name"); simpleHighlightQuery.addProjectionOnField("product_price"); // 設定條件 // 可以使用查詢表示式 // simpleHighlightQuery.addCriteria(new Criteria().expression("product_catalog_name:餐具 AND product_name:水果 AND product_price:[10 TO 50}")); // 也可以使用api simpleHighlightQuery.addCriteria(new Criteria("product_catalog_name").is("餐具")) .addCriteria(new Criteria("product_name").is("水果")) .addCriteria(new Criteria("product_price").between(10,50,true,false)); // 設定高亮 HighlightOptions highlightOptions = new HighlightOptions(); highlightOptions.setSimplePrefix("<span style='color:red;'>"); highlightOptions.setSimplePostfix("</span>"); highlightOptions.addField("product_catalog_name","product_name"); simpleHighlightQuery.setHighlightOptions(highlightOptions); // 查詢 HighlightPage<Product> new_core = solrTemplate.queryForHighlightPage("new_core", simpleHighlightQuery, Product.class); // 列印結果 System.err.println("總記錄數:" + new_core.getTotalElements()); for (Product product : new_core.getContent()) { // 獲取高亮部分,是不會合併到源文件中的 List<HighlightEntry.Highlight> highlights = new_core.getHighlights(product); highlights.stream().forEach((highlight)->{ highlight.getSnipplets().forEach(System.err::print); System.err.println(); }); System.err.println(product); System.err.println(); } } @Getter @Setter @AllArgsConstructor class User{ @Field("id") private String id; @Field("my_name") private String name; @Field("my_title") private String title; } @Getter @Setter @ToString @AllArgsConstructor class Product{ @Field("id") private String id; @Field("product_catalog_name") private String catalogName; @Field("product_price") private Double price; @Field("product_name") private String name; @Field("product_description") private String description; @Field("product_picture") private String picture; } }
以上便是全部了,如果哪裡寫錯了,請留言說明,我進行修改,謝謝。
&n