1. Ideas for searching article content
The previous article talked about how to integrate ES 5 on Spring Boot 2.0. This article talks about the specific practical measures. Let’s briefly talk about how to implement the specific implementation of articles and questions and answers. The implementation idea is very simple:
If you call search directly here, you can easily find unsatisfactory things. Because content search focuses on the connectivity of content. So the processing method here is relatively low, and I hope to achieve a better search method with more communication. It is to get many phrases through word participle, and then use phrases to accurately match phrases.
ES installation of the IK word segmenter plug-in is very simple. The first step is to download the corresponding version https://github.com/medcl/elasticsearch-analysis-ik/releases. The second step is to create a new folder ik in the elasticsearch-5.5.3/plugins directory, and copy the unzipped file of elasticsearch-analysis-ik-5.5.3.zip to the elasticsearch-5.1.1/plugins/ik directory. Finally restart ES.
2. Search content participle
Install IK, how to call it?
The first step is that when I search for content here, I will pass it in with commas splicing. So the commas will be split first
The second step is to add yourself to the search terms, because some words are gone after ik participle... This is a bug
The third step is to use the AnalyzeRequestBuilder object to obtain the return value object list after the IK participle
Step 4: Optimize the word participle results. For example, if all are words, then keep all; if there are words and words, then keep the words; if there are only words, then keep the words.
The core implementation code is as follows:
/** * Search content participle*/ protected List<String> handlingSearchContent(String searchContent) { List<String> searchTermResultList = new ArrayList<>(); // Split by commas to get the search term list List<String> searchTermList = Arrays.asList(searchContent.split(SearchConstant.STRING_TOKEN_SPLIT)); // If the search term is greater than 1 word, the IK word participle will be obtained by obtaining the word participle result list searchTermList.forEach(searchTerm -> { // Search term TAG Add the search term list itself and solve the problem of will searchTermResultList.add(searchTerm); // Get the search term IK participle list searchTermResultList.addAll(getIkAnalyzeSearchTerms(searchTerm)); }); return searchTermResultList; } /** * Call ES to get the result after IK participle*/ protected List<String> getIkAnalyzeSearchTerms(String searchContent) { AnalyzeRequestBuilder ikRequest = new AnalyzeRequestBuilder(elasticsearchTemplate.getClient(), AnalyzeAction.INSTANCE, SearchConstant.INDEX_NAME, searchContent); ikRequest.setTokenizer(SearchConstant.TOKENIZER_IK_MAX); List<AnalyzeResponse.AnalyzeToken> ikTokenList = ikRequest.execute().actionGet().getTokens(); // Loop assignment List<String> searchTermList = new ArrayList<>(); ikTokenList.forEach(ikToken -> { searchTermList.add(ikToken.getTerm()); }); return handlingIkResultTerms(searchTermList); } /** * If word participle result: shampoo (shampoo, hair, shampoo, hair, water) * - are all words, keep * - words + words, only words * - are all words, keep words */ private List<String> handleIkResultTerms(List<String> searchTermList) { Boolean isPhrase = false; Boolean isWord = false; for (String term : searchTermList) { if (term.length() > SearchConstant.SEARCH_TERM_LENGTH) { isPhrase = true; } else { isWord = true; } } if (isWord & isPhrase) { List<String> phraseList = new ArrayList<>(); searchTermList.forEach(term -> { if (term.length() > SearchConstant.SEARCH_TERM_LENGTH) { phraseList.add(term); } }); return phraseList; } return searchTermList; }3. Search query statement
Construct the content enumeration object and list the fields that need to be searched. The ContentSearchTermEnum code is as follows:
import lombok.AllArgsConstructor;@AllArgsConstructorpublic enum ContentSearchTermEnum { // Title TITLE("title"), // Content CONTENT("content"); /** * Search field*/ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; }}Loop the "Phone Search Match" search field and set the minimum weight value to 1. The core code is as follows:
/** * Construct query conditions*/ private void buildMatchQuery(BoolQueryBuilder queryBuilder, List<String> searchTermList) { for (String searchTerm: searchTermList) { for (ContentSearchTermEnum searchTermEnum: ContentSearchTermEnum.values()) { queryBuilder.should(QueryBuilders.matchPhraseQuery(searchTermEnum.getName(), searchTerm)); } } queryBuilder.minimumShouldMatch(SearchConstant.MINIMUM_SHOULD_MATCH); }4. Filter conditions
There are more than one thing to search for, and sometimes the demand is like this. You need to search under a certain category, such as e-commerce needs to search for products under a certain brand. Then you need to construct some fitlers for filtering. Corresponding to SQL statements, OR and AND, under Where. Use the filter method to add filtering in ES. The code is as follows:
/** * Build filters*/ private void buildFilterQuery(BoolQueryBuilder boolQueryBuilder, Integer type, String category) { // Content type filter if (type != null) { BoolQueryBuilder typeFilterBuilder = QueryBuilders.boolQuery(); typeFilterBuilder.should(QueryBuilders.matchQuery(SearchConstant.TYPE_NAME, type).lenient(true)); boolQueryBuilder.filter(typeFilterBuilder); } // Content category filter if (!StringUtils.isEmpty(category)) { BoolQueryBuilder categoryFilterBuilder = QueryBuilders.boolQuery(); categoryFilterBuilder.should(QueryBuilders.matchQuery(SearchConstant.CATEGORY_NAME, category).lenient(true)); boolQueryBuilder.filter(categoryFilterBuilder); } }type is a large class and category is a small class, so that it can support size and class filtering. But what if you need to search in type = 1 or type = 2? The specific implementation code is very simple:
typeFilterBuilder .should(QueryBuilders.matchQuery(SearchConstant.TYPE_NAME, 1) .should(QueryBuilders.matchQuery(SearchConstant.TYPE_NAME, 2) .lenient(true));
Through chain expressions, two should implement or, that is, the OR statement corresponding to SQL. Implementation of the AND statement corresponding to SQL is achieved through two BoolQueryBuilders.
5. Paging and sorting conditions
The paging sorting code is very simple:
@Override public PageBean searchContent(ContentSearchBean contentSearchBean) { Integer pageNumber = contentSearchBean.getPageNumber(); Integer pageSize = contentSearchBean.getPageSize(); PageBean<ContentEntity> resultPageBean = new PageBean<>(); resultPageBean.setPageNumber(pageNumber); resultPageBean.setPageSize(pageSize); // Construct search phrase String searchContent = contentSearchBean.getSearchContent(); List<String> searchTermList = handlingSearchContent(searchContent); // Build query conditions BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); buildMatchQuery(boolQueryBuilder, searchTermList); // Build filter conditions buildFilterQuery(boolQueryBuilder, contentSearchBean.getType(), contentSearchBean.getCategory()); // Build paging and sorting conditions Pageable pageable = PageRequest.of(pageNumber, pageSize); if (!StringUtils.isEmpty(contentSearchBean.getOrderName())) { pageable = PageRequest.of(pageNumber, pageSize, Sort.Direction.DESC, contentSearchBean.getOrderName()); } SearchQuery searchQuery = new NativeSearchQueryBuilder().withPageable(pageable) .withQuery(boolQueryBuilder).build(); // Search LOGGER.info("/n ContentServiceImpl.searchContent() [" + searchContent + "] /n DSL = /n " + searchQuery.getQuery().toString()); Page<ContentEntity> contentPage = contentRepository.search(searchQuery); resultPageBean.setResult(contentPage.getContent()); resultPageBean.setTotalCount((int) contentPage.getTotalElements()); resultPageBean.setTotalPage((int) contentPage.getTotalElements()); resultPageBean.setTotalPage((int) contentPage.getTotalElements() / resultPageBean.getPageSize() + 1); return resultPageBean; }Use the Pageable object to construct paging parameters and specify the corresponding sorting fields and sorting order (DESC ASC).
6. Summary
This idea is relatively simple. I hope it will be helpful to everyone's learning, and I hope everyone will support Wulin.com more.