java通过Solr的Suggest实现提示词

本文介绍如何使用Solr 4.10.4版本提供的Suggest功能实现Web端及移动端的搜索建议。通过配置solrconfig.xml文件并利用提示词文件构建搜索索引,能够支持用户输入汉字或汉字拼音首字母时提供关联词提示。
需求:在Web端或移动设备上实现用户输入汉字或汉字的首字母,提供关联词提示。 

解决方案:通过Solr提供的Suggest实现此功能,Solr版本为4.10.4 

在Solr的配置文件solrconfig.xml文件中修改Suggest的配置,通过提示词文件构建搜索索引

<searchComponent name="suggest" class="solr.SuggestComponent">
<lst name="suggester">
  <str name="name">mySuggester</str>
  <str name="lookupImpl">AnalyzingLookupFactory</str>
  <str name="dictionaryImpl">FileDictionaryFactory</str>
  <str name="field">suggest</str>
  <str name="sourceLocation">suggest.txt</str>
  <str name="suggestAnalyzerFieldType">string</str>
  <str name="buildOnOptimize">false</str>
</lst>
</searchComponent>
<requestHandler name="/suggest" class="solr.SearchHandler" startup="lazy">
<lst name="defaults">
  <str name="suggest">true</str>
  <str name="suggest.count">5</str>
</lst>
<arr name="components">
  <str>suggest</str>
</arr>
</requestHandler>

参数说明: 
name:suggester的名字,如果设置多个,可以在请求中指定。 
lookupImpl:查找方式的具体实现 
dictionaryImpl:字典的具体实现 
field:搜索的字段 
sourceLocation:字典文件 
suggestAnalyzerFieldType:字段的类型 
buildOnOptimize:何时创建拼写索引 
suggest.count:返回的搜索结果的数量 

因为要同时提供汉字和汉字拼音首字母的搜索,因此在构建字典文件时需要进行特殊处理,字典文件样例如下: 

abesb|阿巴二氏病
阿巴二氏病|abesb
abkw|阿巴卡韦
阿巴卡韦|abkw
abkwsfd|阿巴卡韦双夫定
阿巴卡韦双夫定|abkwsfd
abkwsfdp|阿巴卡韦双夫定片
阿巴卡韦双夫定片|abkwsfdp


这样做就从业务需求上可以满足,但索引量成倍增多,在数据量不是特别大的时候性能问题基本可以忽略。 
搜索测试的链接如下: 
http://127.0.0.1:8080/solr/metis/suggest?qt=suggest&suggest.dictionary=mySuggester&wt=json&suggest.q=天 
返回结果如下: 

{
- responseHeader:  {
    - status: 0,
    - QTime: 1
- },
- suggest:  {
    - mySuggester:  {
        - 天:  {
            - numFound: 5,
            - suggestions:  [
                - {
                    - term: "天一止咳|tyzk",
                    - weight: 1,
                    - payload: ""
                - },
                - {
                    - term: "天一止咳糖浆|tyzktj",
                    - weight: 1,
                    - payload: ""
                - },
                - {
                    - term: "天丹通络|tdtl",
                    - weight: 1,
                    - payload: ""
                - },
                - {
                    - term: "天丹通络胶囊|tdtljn",
                    - weight: 1,
                    - payload: ""
                - },
                - {
                    - term: "天仙藤|txt",
                    - weight: 1,
                    - payload: ""
                - }
            - ]
        - }
    - }
- }
}


页面上通过jQuery的Autocomplete功能实现。 
页面代码如下: 
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
    <link rel="stylesheet" href="./css/jquery-ui.css"/>
    <script src="./js/jquery-1.8.3.js"></script>
    <script src="./js/jquery-ui.js"></script>
    <script>
        $(function () {
            $("#tags").autocomplete({
                minLength: 0,
                delay: 100,
                source: []
            });
        });
    </script>
</head>
<body>
<div class="ui-widget">
    <label for="tags">Tags: </label>
    <input type="text" id="tags" oninput="search(this.value)"/>
</div>
</body>
<script>
    require('./renderer.js');
    require('devtron').install()
    var suggest = require('./apps/suggest/suggest.js');

    var search = function (keyword) {
        suggest.search(keyword).then(function (data) {
            console.log(data);
            $("#tags").autocomplete("option", "source", data);
        }, function (error) {
            console.error(error);
        });
    }
</script>
</html>

JavaScript部分的代码如下,需要对搜索结果的词进行格式化,这部分功能也可以通过后端实现,但性能没有前端从Solr获取结果处理快: 

const http = require('http'),
    qs = require('querystring');

var Suggest = exports;

Suggest.search = function (keyword) {
    var data = {
        qt: 'suggest',
        'suggest.dictionary': 'mySuggester',
        'wt': 'json',
        'suggest.q': keyword
    };

    var content = qs.stringify(data);

    var options = {
        hostname: '127.0.0.1',
        port: 8080,
        path: '/solr/metis/suggest?' + content,
        method: 'GET'
    };

    var result = [];
    var promise = new Promise(function (resolve, reject) {
        var req = http.request(options, function (res) {
            res.on('data', function (chunk) {
                result = convert(keyword, chunk);
                resolve(result);
            });
        });

        req.on('error', function (e) {
            reject(new Error(e.message));
        });

        req.end();
    });

    return promise;
};

function convert(keyword, data) {
    var result = [];
    var json = JSON.parse(String(data));
    var num = parseInt(json.suggest.mySuggester[keyword].numFound);
    if (num > 0) {
        var matcher = new RegExp("^[A-Za-z0-9]+$", "i");
        var tmp = json.suggest.mySuggester[keyword].suggestions;
        for (var i = 0; i < tmp.length; i++) {
            var d = tmp[i]['term'].split('\|');
            if (matcher.test(d[0])) {
                var obj = {
                    label: d[0],
                    value: d[1]
                };
                result.push(obj);
            } else {
                result.push(d[0]);
            }
        }
    }

    return result;
}


### 使用Java实现Solr相关功能的教程与代码示例 #### 1. 初始化Solr客户端 在Java中,可以通过`HttpSolrClient`或`ConcurrentUpdateSolrClient`来连接和操作Solr服务。`HttpSolrClient`适用于简单的查询和更新操作,而`ConcurrentUpdateSolrClient`则适用于需要高并发写入的场景。 以下是一个使用`HttpSolrClient`初始化Solr客户端的示例: ```java import org.apache.solr.client.solrj.impl.HttpSolrClient; public class SolrClientExample { public static void main(String[] args) { String solrUrl = "http://localhost:8983/solr/my_core"; HttpSolrClient solrClient = new HttpSolrClient.Builder(solrUrl).build(); } } ``` 对于需要批量提交数据的场景,可以使用`ConcurrentUpdateSolrClient`,它支持异步提交和多线程处理: ```java import org.apache.solr.client.solrj.impl.ConcurrentUpdateSolrClient; public class ConcurrentSolrClientExample { public static void main(String[] args) { String solrUrl = "http://localhost:8983/solr/my_core"; ConcurrentUpdateSolrClient solrClient = new ConcurrentUpdateSolrClient.Builder(solrUrl) .withQueueSize(1000) .withThreadCount(4) .build(); } } ``` #### 2. 添加文档到SolrJava中,可以通过`SolrInputDocument`来构建文档并使用`SolrClient`将其添加到Solr中。 ```java import org.apache.solr.common.SolrInputDocument; import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrServerException; import java.io.IOException; public class AddDocumentExample { public static void main(String[] args) throws IOException, SolrServerException { String solrUrl = "http://localhost:8983/solr/my_core"; SolrClient solrClient = new HttpSolrClient.Builder(solrUrl).build(); SolrInputDocument document = new SolrInputDocument(); document.addField("id", "001"); document.addField("name", "Sample Document"); document.addField("content", "This is a sample document for Solr indexing."); solrClient.add(document); solrClient.commit(); } } ``` #### 3. 查询Solr数据 使用`SolrQuery`类可以构建查询条件,并通过`SolrClient`执行查询。 ```java import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.common.SolrDocumentList; public class QuerySolrExample { public static void main(String[] args) throws Exception { String solrUrl = "http://localhost:8983/solr/my_core"; SolrClient solrClient = new HttpSolrClient.Builder(solrUrl).build(); SolrQuery query = new SolrQuery(); query.setQuery("name:Sample Document"); QueryResponse response = solrClient.query(query); SolrDocumentList results = response.getResults(); System.out.println("Found " + results.getNumFound() + " documents."); for (int i = 0; i < results.size(); ++i) { System.out.println(results.get(i)); } } } ``` #### 4. 删除Solr文档 可以通过`deleteById`或`deleteByQuery`方法删除Solr中的文档。 ```java import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrServerException; import java.io.IOException; public class DeleteDocumentExample { public static void main(String[] args) throws IOException, SolrServerException { String solrUrl = "http://localhost:8983/solr/my_core"; SolrClient solrClient = new HttpSolrClient.Builder(solrUrl).build(); // 删除指定ID的文档 solrClient.deleteById("001"); solrClient.commit(); // 或者删除符合特定查询条件的文档 solrClient.deleteByQuery("name:Sample Document"); solrClient.commit(); } } ``` #### 5. 关闭Solr连接 在完成操作后,务必关闭Solr客户端以释放资源。 ```java import org.apache.solr.client.solrj.SolrClient; public class CloseSolrClientExample { public static void main(String[] args) throws Exception { String solrUrl = "http://localhost:8983/solr/my_core"; SolrClient solrClient = new HttpSolrClient.Builder(solrUrl).build(); // 执行操作... solrClient.close(); // 关闭Solr客户端[^1] } } ``` #### 6. 集成中文分词 为了支持中文分词,可以集成HanLP插件[^2]。具体步骤包括下载HanLP的Solr插件,将其放置在Solr的`lib`目录下,并在`schema.xml`中配置相应的分词器。 ```xml <fieldType name="text_hanlp" class="solr.TextField"> <analyzer> <tokenizer class="org.apache.lucene.analysis.cn.smart.HanLPChineseTokenizerFactory"/> </analyzer> </fieldType> ``` 在Java代码中,可以直接使用已配置的字段类型进行查询和索引操作。 #### 7. 多Core操作 如果Solr中配置了多个Core,可以通过指定不同的Core名称来操作不同的索引库。 ```java import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.impl.HttpSolrClient; public class MultiCoreExample { public static void main(String[] args) throws Exception { String core1Url = "http://localhost:8983/solr/core1"; String core2Url = "http://localhost:8983/solr/core2"; SolrClient core1Client = new HttpSolrClient.Builder(core1Url).build(); SolrClient core2Client = new HttpSolrClient.Builder(core2Url).build(); // 对core1执行操作 // ... // 对core2执行操作 // ... core1Client.close(); core2Client.close(); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值