• springboot整合MeiliSearch轻量级搜索引擎


    一、MeilisearchEasy Search点击进入官网了解,本文主要从小微型公司业务出发,选择meilisearch来作为项目的全文搜索引擎,还可以当成来mongodb来使用。

    二、starter封装

    1、项目结构展示

    2、引入依赖包(我是有包统一管理的fastjson用的1.2.83,gson用的2.8.6)

    1. <dependencies>
    2. <dependency>
    3. <groupId>cn.iocoder.boot</groupId>
    4. <artifactId>yudao-common</artifactId>
    5. </dependency>
    6. <!-- meilisearch 轻量级搜索 -->
    7. <!-- https://mvnrepository.com/artifact/com.meilisearch.sdk/meilisearch-java -->
    8. <dependency>
    9. <groupId>com.meilisearch.sdk</groupId>
    10. <artifactId>meilisearch-java</artifactId>
    11. <version>0.11.2</version>
    12. </dependency>
    13. <!-- https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2 -->
    14. <dependency>
    15. <groupId>com.alibaba</groupId>
    16. <artifactId>fastjson</artifactId>
    17. </dependency>
    18. <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
    19. <dependency>
    20. <groupId>com.google.code.gson</groupId>
    21. <artifactId>gson</artifactId>
    22. </dependency>
    23. <!-- Web 相关 -->
    24. <dependency>
    25. <groupId>cn.iocoder.boot</groupId>
    26. <artifactId>yudao-spring-boot-starter-web</artifactId>
    27. <scope>provided</scope> <!-- 设置为 provided,只有 OncePerRequestFilter 使用到 -->
    28. </dependency>
    29. </dependencies>

    3、yml参数读取代码参考

    1. import lombok.Data;
    2. import org.springframework.boot.context.properties.ConfigurationProperties;
    3. import org.springframework.validation.annotation.Validated;
    4. /**
    5. * MeiliSearch 自动装配参数类
    6. * 2023年9月21日
    7. */
    8. @ConfigurationProperties("yudao.meilisearch")
    9. @Data
    10. @Validated
    11. public class MeiliSearchProperties {
    12. /**
    13. * 主机地址
    14. */
    15. private String hostUrl;
    16. /**
    17. * 接口访问标识
    18. */
    19. private String apiKey;
    20. }

    4、自动配置类代码参考

    1. import com.meilisearch.sdk.Client;
    2. import com.meilisearch.sdk.Config;
    3. import org.springframework.boot.autoconfigure.AutoConfiguration;
    4. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    5. import org.springframework.boot.context.properties.EnableConfigurationProperties;
    6. import org.springframework.cache.annotation.EnableCaching;
    7. import org.springframework.context.annotation.Bean;
    8. import javax.annotation.Resource;
    9. /**
    10. * MeiliSearch 自动装配类
    11. * 2023年9月21日
    12. */
    13. @AutoConfiguration
    14. @EnableConfigurationProperties({MeiliSearchProperties.class})
    15. @EnableCaching
    16. public class MeiliSearchAutoConfiguration {
    17. @Resource
    18. MeiliSearchProperties properties;
    19. @Bean
    20. @ConditionalOnMissingBean(Client.class)
    21. Client client() {
    22. return new Client(config());
    23. }
    24. @Bean
    25. @ConditionalOnMissingBean(Config.class)
    26. Config config() {
    27. return new Config(properties.getHostUrl(), properties.getApiKey());
    28. }
    29. }

    5、数据处理类参考

    1. import java.util.List;
    2. /**
    3. * MeiliSearch json解析类
    4. * 2023年9月21日
    5. */
    6. public class JsonHandler {
    7. private com.meilisearch.sdk.json.JsonHandler jsonHandler = new MyGsonJsonHandler();
    8. public <T> SearchResult<T> resultDecode(String o, Class<T> clazz) {
    9. Object result = null;
    10. try {
    11. result = jsonHandler.decode(o, SearchResult.class, clazz);
    12. } catch (Exception e) {
    13. e.printStackTrace();
    14. }
    15. return result == null ? null : (SearchResult<T>) result;
    16. }
    17. public <T> List<T> listDecode(Object o, Class<T> clazz) {
    18. Object list = null;
    19. try {
    20. list = jsonHandler.decode(o, List.class, clazz);
    21. } catch (Exception e) {
    22. e.printStackTrace();
    23. }
    24. return list == null ? null : (List<T>) list;
    25. }
    26. public String encode(Object o) {
    27. try {
    28. return jsonHandler.encode(o);
    29. } catch (Exception e) {
    30. e.printStackTrace();
    31. return null;
    32. }
    33. }
    34. public <T> T decode(Object o, Class<T> clazz) {
    35. T t = null;
    36. try {
    37. t = jsonHandler.decode(o, clazz);
    38. } catch (Exception e) {
    39. e.printStackTrace();
    40. }
    41. return t;
    42. }
    43. }

    6、MyGsonJsonHandler类改写基本没啥用(meilisearch通过官方sdk到springboot的雪花id会丢失精度,我是加了冗余字段把雪花id存进去当主键用的。还有就是LocalDateTime不用大于小于范围查询,我是把要范围查询的时间字段冗余成long类型),有对LocalDateTime和雪花id Long存储有更好的解决方案的欢迎留言。

    1. import com.alibaba.fastjson.JSON;
    2. import com.google.gson.*;
    3. import com.google.gson.reflect.TypeToken;
    4. import com.meilisearch.sdk.exceptions.JsonDecodingException;
    5. import com.meilisearch.sdk.exceptions.JsonEncodingException;
    6. import com.meilisearch.sdk.exceptions.MeilisearchException;
    7. import com.meilisearch.sdk.model.Key;
    8. import java.lang.reflect.Type;
    9. import java.time.LocalDateTime;
    10. import java.time.format.DateTimeFormatter;
    11. public class MyGsonJsonHandler implements com.meilisearch.sdk.json.JsonHandler {
    12. private Gson gson;
    13. public MyGsonJsonHandler() {
    14. GsonBuilder gsonBuilder = new GsonBuilder();
    15. gsonBuilder.registerTypeAdapter(LocalDateTime.class, (JsonDeserializer<LocalDateTime>) (json, typeOfT, context) ->
    16. LocalDateTime.parse(json.getAsJsonPrimitive().getAsString(), DateTimeFormatter.ISO_DATE_TIME));
    17. // gsonBuilder.registerTypeAdapter(Long.class, (JsonDeserializer<Long>) (json, typeOfT, context) -> {
    18. // Long parse = Long.parseLong(json.getAsJsonPrimitive().getAsString());
    19. // 雪花id科学计数后转支付串会丢失进度小1啥的
    20. // return parse;
    21. // });
    22. this.gson = gsonBuilder.create();
    23. }
    24. public String encode(Object o) throws MeilisearchException {
    25. if (o != null && o.getClass() == String.class) {
    26. return (String) o;
    27. } else {
    28. if (o != null && o.getClass() == Key.class) {
    29. Key key = (Key) o;
    30. if (key.getExpiresAt() == null) {
    31. JsonElement jsonElement = this.gson.toJsonTree(o);
    32. JsonObject jsonObject = jsonElement.getAsJsonObject();
    33. jsonObject.add("expiresAt", JsonNull.INSTANCE);
    34. o = jsonObject;
    35. }
    36. }
    37. try {
    38. return JSON.toJSONString(o);
    39. } catch (Exception var6) {
    40. throw new JsonEncodingException(var6);
    41. }
    42. }
    43. }
    44. public <T> T decode(Object o, Class<?> targetClass, Class<?>... parameters) throws MeilisearchException {
    45. if (o == null) {
    46. throw new JsonDecodingException("Response to deserialize is null");
    47. } else if (targetClass == String.class) {
    48. return (T) o;
    49. } else {
    50. try {
    51. if (parameters != null && parameters.length != 0) {
    52. TypeToken<?> parameterized = TypeToken.getParameterized(targetClass, parameters);
    53. Type type = parameterized.getType();
    54. String json = this.gson.toJson(o);
    55. json = json.replace("\\", "");
    56. //去除json首位字符串
    57. json = json.substring(1, json.length() - 1);
    58. String string = o.toString();
    59. return this.gson.fromJson(string, type);
    60. // return JSON.parseObject(string, type);
    61. } else {
    62. return (T) JSON.parseObject((String) o, targetClass);
    63. }
    64. } catch (JsonSyntaxException var5) {
    65. throw new JsonDecodingException(var5);
    66. }
    67. }
    68. }
    69. }

    7、自定义注解代码参考

    1. import java.lang.annotation.*;
    2. /**
    3. * MeiliSearch
    4. * 2023年9月21日
    5. */
    6. @Documented
    7. @Target(ElementType.FIELD)
    8. @Retention(RetentionPolicy.RUNTIME)
    9. public @interface MSFiled {
    10. /**
    11. * 是否开启过滤
    12. */
    13. boolean openFilter() default false;
    14. /**
    15. * 是否不展示
    16. */
    17. boolean noDisplayed() default false;
    18. /**
    19. * 是否开启排序
    20. */
    21. boolean openSort() default false;
    22. /**
    23. * 处理的字段名
    24. */
    25. String key() ;
    26. }
    27. import java.lang.annotation.*;
    28. /**
    29. * MeiliSearch
    30. * 2023年9月21日
    31. */
    32. @Documented
    33. @Target(ElementType.TYPE)
    34. @Retention(RetentionPolicy.RUNTIME)
    35. public @interface MSIndex {
    36. /**
    37. * 索引
    38. */
    39. String uid() default "";
    40. /**
    41. * 主键
    42. */
    43. String primaryKey() default "";
    44. /**
    45. * 分类最大数量
    46. */
    47. int maxValuesPerFacet() default 100;
    48. /**
    49. * 单次查询最大数量
    50. */
    51. int maxTotalHits() default 1000;
    52. }

    8、返回结果解析类参考

    1. import java.util.List;
    2. /**
    3. * MeiliSearch
    4. * 2023年9月21日
    5. */
    6. public class SearchResult {
    7. private String query;
    8. private long offset;
    9. private long limit;
    10. private long processingTimeMs;
    11. private long nbHits;
    12. private long hitsPerPage;
    13. private long page;
    14. private long totalPages;
    15. private long totalHits;
    16. private boolean exhaustiveNbHits;
    17. private List hits;
    18. public String getQuery() {
    19. return query;
    20. }
    21. public void setQuery(String query) {
    22. this.query = query;
    23. }
    24. public long getOffset() {
    25. return offset;
    26. }
    27. public void setOffset(long offset) {
    28. this.offset = offset;
    29. }
    30. public long getLimit() {
    31. return limit;
    32. }
    33. public void setLimit(long limit) {
    34. this.limit = limit;
    35. }
    36. public long getProcessingTimeMs() {
    37. return processingTimeMs;
    38. }
    39. public void setProcessingTimeMs(long processingTimeMs) {
    40. this.processingTimeMs = processingTimeMs;
    41. }
    42. public long getNbHits() {
    43. return nbHits;
    44. }
    45. public void setNbHits(long nbHits) {
    46. this.nbHits = nbHits;
    47. }
    48. public boolean isExhaustiveNbHits() {
    49. return exhaustiveNbHits;
    50. }
    51. public void setExhaustiveNbHits(boolean exhaustiveNbHits) {
    52. this.exhaustiveNbHits = exhaustiveNbHits;
    53. }
    54. public List getHits() {
    55. return hits;
    56. }
    57. public void setHits(List hits) {
    58. this.hits = hits;
    59. }
    60. @Override
    61. public String toString() {
    62. return "SearchResult{" +
    63. "query='" + query + '\'' +
    64. ", offset=" + offset +
    65. ", limit=" + limit +
    66. ", processingTimeMs=" + processingTimeMs +
    67. ", nbHits=" + nbHits +
    68. ", exhaustiveNbHits=" + exhaustiveNbHits +
    69. ", hits=" + hits +
    70. '}';
    71. }
    72. public long getHitsPerPage() {
    73. return hitsPerPage;
    74. }
    75. public void setHitsPerPage(long hitsPerPage) {
    76. this.hitsPerPage = hitsPerPage;
    77. }
    78. public long getPage() {
    79. return page;
    80. }
    81. public void setPage(long page) {
    82. this.page = page;
    83. }
    84. public long getTotalPages() {
    85. return totalPages;
    86. }
    87. public void setTotalPages(long totalPages) {
    88. this.totalPages = totalPages;
    89. }
    90. public long getTotalHits() {
    91. return totalHits;
    92. }
    93. public void setTotalHits(long totalHits) {
    94. this.totalHits = totalHits;
    95. }
    96. }

    9、基础操作接口封装

    1. import cn.iocoder.yudao.framework.meilisearch.json.SearchResult;
    2. import com.meilisearch.sdk.SearchRequest;
    3. import com.meilisearch.sdk.model.Settings;
    4. import com.meilisearch.sdk.model.Task;
    5. import com.meilisearch.sdk.model.TaskInfo;
    6. import java.util.List;
    7. /**
    8. * MeiliSearch 基础接口
    9. * 2023年9月21日
    10. */
    11. interface DocumentOperations<T> {
    12. T get(String identifier);
    13. List<T> list();
    14. List<T> list(int limit);
    15. List<T> list(int offset, int limit);
    16. long add(T document);
    17. long update(T document);
    18. long add(List<T> documents);
    19. long update(List<T> documents);
    20. long delete(String identifier);
    21. long deleteBatch(String... documentsIdentifiers);
    22. long deleteAll();
    23. SearchResult<T> search(String q);
    24. SearchResult<T> search(String q, int offset, int limit);
    25. SearchResult<T> search(SearchRequest sr);
    26. String select(SearchRequest sr);
    27. Settings getSettings();
    28. TaskInfo updateSettings(Settings settings);
    29. TaskInfo resetSettings();
    30. Task getUpdate(int updateId);
    31. // UpdateStatus updateSettings(Settings settings);
    32. //
    33. // UpdateStatus resetSettings();
    34. //
    35. // UpdateStatus getUpdate(int updateId);
    36. //
    37. // UpdateStatus[] getUpdates();
    38. }

    10、基本操作实现

    1. import cn.hutool.core.util.ObjectUtil;
    2. import cn.iocoder.yudao.framework.meilisearch.json.JsonHandler;
    3. import cn.iocoder.yudao.framework.meilisearch.json.MSFiled;
    4. import cn.iocoder.yudao.framework.meilisearch.json.MSIndex;
    5. import cn.iocoder.yudao.framework.meilisearch.json.SearchResult;
    6. import com.alibaba.fastjson.JSON;
    7. import com.meilisearch.sdk.Client;
    8. import com.meilisearch.sdk.Index;
    9. import com.meilisearch.sdk.SearchRequest;
    10. import com.meilisearch.sdk.model.*;
    11. import org.springframework.beans.factory.InitializingBean;
    12. import org.springframework.util.StringUtils;
    13. import javax.annotation.Resource;
    14. import java.lang.reflect.Field;
    15. import java.lang.reflect.ParameterizedType;
    16. import java.util.*;
    17. /**
    18. * MeiliSearch 基本操作实现
    19. * 2023年9月21日
    20. */
    21. public class MeilisearchRepository<T> implements InitializingBean, DocumentOperations<T> {
    22. private Index index;
    23. private Class<T> tClass;
    24. private JsonHandler jsonHandler = new JsonHandler();
    25. @Resource
    26. private Client client;
    27. @Override
    28. public T get(String identifier) {
    29. T document;
    30. try {
    31. document = getIndex().getDocument(identifier, tClass);
    32. } catch (Exception e) {
    33. throw new RuntimeException(e);
    34. }
    35. return document;
    36. }
    37. @Override
    38. public List<T> list() {
    39. List<T> documents;
    40. try {
    41. documents = Optional.ofNullable(getIndex().getDocuments(tClass))
    42. .map(indexDocument -> indexDocument.getResults())
    43. .map(result -> Arrays.asList(result))
    44. .orElse(new ArrayList<>());
    45. } catch (Exception e) {
    46. throw new RuntimeException(e);
    47. }
    48. return documents;
    49. }
    50. @Override
    51. public List<T> list(int limit) {
    52. List<T> documents;
    53. try {
    54. DocumentsQuery query = new DocumentsQuery();
    55. query.setLimit(limit);
    56. documents = Optional.ofNullable(index.getDocuments(query, tClass))
    57. .map(indexDocument -> indexDocument.getResults())
    58. .map(result -> Arrays.asList(result))
    59. .orElse(new ArrayList<>());
    60. } catch (Exception e) {
    61. throw new RuntimeException(e);
    62. }
    63. return documents;
    64. }
    65. @Override
    66. public List<T> list(int offset, int limit) {
    67. List<T> documents;
    68. try {
    69. DocumentsQuery query = new DocumentsQuery();
    70. query.setLimit(limit);
    71. query.setOffset(offset);
    72. documents = Optional.ofNullable(getIndex().getDocuments(query, tClass))
    73. .map(indexDocument -> indexDocument.getResults())
    74. .map(result -> Arrays.asList(result))
    75. .orElse(new ArrayList<>());
    76. } catch (Exception e) {
    77. throw new RuntimeException(e);
    78. }
    79. return documents;
    80. }
    81. @Override
    82. public long add(T document) {
    83. List<T> list = Collections.singletonList(document);
    84. return add(list);
    85. }
    86. @Override
    87. public long update(T document) {
    88. List<T> list = Collections.singletonList(document);
    89. return update(list);
    90. }
    91. @Override
    92. public long add(List documents) {
    93. try {
    94. if (ObjectUtil.isNotNull(documents)) {
    95. String jsonString = JSON.toJSONString(documents);
    96. if (ObjectUtil.isNotNull(jsonString)) {
    97. TaskInfo taskInfo = getIndex().addDocuments(jsonString);
    98. if (ObjectUtil.isNotNull(taskInfo)) {
    99. return taskInfo.getTaskUid();
    100. }
    101. }
    102. }
    103. } catch (Exception e) {
    104. throw new RuntimeException(documents.toString(), e);
    105. }
    106. return 0;
    107. }
    108. @Override
    109. public long update(List documents) {
    110. int updates;
    111. try {
    112. updates = getIndex().updateDocuments(JSON.toJSONString(documents)).getTaskUid();
    113. } catch (Exception e) {
    114. throw new RuntimeException(e);
    115. }
    116. return updates;
    117. }
    118. @Override
    119. public long delete(String identifier) {
    120. int taskId;
    121. try {
    122. taskId = getIndex().deleteDocument(identifier).getTaskUid();
    123. } catch (Exception e) {
    124. throw new RuntimeException(e);
    125. }
    126. return taskId;
    127. }
    128. @Override
    129. public long deleteBatch(String... documentsIdentifiers) {
    130. int taskId;
    131. try {
    132. taskId = getIndex().deleteDocuments(Arrays.asList(documentsIdentifiers)).getTaskUid();
    133. } catch (Exception e) {
    134. throw new RuntimeException(e);
    135. }
    136. return taskId;
    137. }
    138. @Override
    139. public long deleteAll() {
    140. int taskId;
    141. try {
    142. taskId = getIndex().deleteAllDocuments().getTaskUid();
    143. } catch (Exception e) {
    144. throw new RuntimeException(e);
    145. }
    146. return taskId;
    147. }
    148. @Override
    149. public cn.iocoder.yudao.framework.meilisearch.json.SearchResult<T> search(String q) {
    150. String result;
    151. try {
    152. result = JSON.toJSONString(getIndex().search(q));
    153. } catch (Exception e) {
    154. throw new RuntimeException(e);
    155. }
    156. return jsonHandler.resultDecode(result, tClass);
    157. }
    158. @Override
    159. public cn.iocoder.yudao.framework.meilisearch.json.SearchResult<T> search(String q, int offset, int limit) {
    160. SearchRequest searchRequest = SearchRequest.builder()
    161. .q(q)
    162. .offset(offset)
    163. .limit(limit)
    164. .build();
    165. return search(searchRequest);
    166. }
    167. // @Override
    168. public cn.iocoder.yudao.framework.meilisearch.json.SearchResult<T> searchPage(String q) {
    169. SearchRequest searchRequest = SearchRequest.builder()
    170. .q(q)
    171. .build();
    172. return search(searchRequest);
    173. }
    174. @Override
    175. public SearchResult<T> search(SearchRequest sr) {
    176. String result;
    177. try {
    178. result = "";
    179. if (ObjectUtil.isNotNull(sr)) {
    180. if (ObjectUtil.isNull(getIndex())) {
    181. initIndex();
    182. }
    183. Searchable search = getIndex().search(sr);
    184. String jsonString = JSON.toJSONString(search);
    185. result = jsonString;
    186. }
    187. } catch (Exception e) {
    188. throw new RuntimeException(e);
    189. }
    190. return jsonHandler.resultDecode(result, tClass);
    191. }
    192. @Override
    193. public String select(SearchRequest sr) {
    194. try {
    195. if (ObjectUtil.isNotNull(sr)) {
    196. if (ObjectUtil.isNull(getIndex())) {
    197. initIndex();
    198. }
    199. Searchable search = getIndex().search(sr);
    200. String jsonString = JSON.toJSONString(search);
    201. return jsonString;
    202. }
    203. } catch (Exception e) {
    204. throw new RuntimeException(e);
    205. }
    206. return null;
    207. }
    208. @Override
    209. public Settings getSettings() {
    210. try {
    211. return getIndex().getSettings();
    212. } catch (Exception e) {
    213. throw new RuntimeException(e);
    214. }
    215. }
    216. @Override
    217. public TaskInfo updateSettings(Settings settings) {
    218. try {
    219. return getIndex().updateSettings(settings);
    220. } catch (Exception e) {
    221. throw new RuntimeException(e);
    222. }
    223. }
    224. @Override
    225. public TaskInfo resetSettings() {
    226. try {
    227. return getIndex().resetSettings();
    228. } catch (Exception e) {
    229. throw new RuntimeException(e);
    230. }
    231. }
    232. @Override
    233. public Task getUpdate(int updateId) {
    234. try {
    235. return getIndex().getTask(updateId);
    236. } catch (Exception e) {
    237. throw new RuntimeException(e);
    238. }
    239. }
    240. @Override
    241. public void afterPropertiesSet() throws Exception {
    242. initIndex();
    243. }
    244. public Index getIndex() {
    245. if (ObjectUtil.isNull(index)) {
    246. try {
    247. initIndex();
    248. } catch (Exception e) {
    249. throw new RuntimeException(e);
    250. }
    251. }
    252. return index;
    253. }
    254. /**
    255. * 初始化索引信息
    256. *
    257. * @throws Exception
    258. */
    259. private void initIndex() throws Exception {
    260. Class<? extends MeilisearchRepository> clazz = getClass();
    261. tClass = (Class<T>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
    262. MSIndex annoIndex = tClass.getAnnotation(MSIndex.class);
    263. String uid = annoIndex.uid();
    264. String primaryKey = annoIndex.primaryKey();
    265. if (StringUtils.isEmpty(uid)) {
    266. uid = tClass.getSimpleName().toLowerCase();
    267. }
    268. if (StringUtils.isEmpty(primaryKey)) {
    269. primaryKey = "id";
    270. }
    271. int maxTotalHit = 1000;
    272. int maxValuesPerFacet = 100;
    273. if (Objects.nonNull(annoIndex.maxTotalHits())) {
    274. maxTotalHit = annoIndex.maxTotalHits();
    275. }
    276. if (Objects.nonNull(annoIndex.maxValuesPerFacet())) {
    277. maxValuesPerFacet = 100;
    278. }
    279. List<String> filterKey = new ArrayList<>();
    280. List<String> sortKey = new ArrayList<>();
    281. List<String> noDisPlay = new ArrayList<>();
    282. //获取类所有属性
    283. for (Field field : tClass.getDeclaredFields()) {
    284. //判断是否存在这个注解
    285. if (field.isAnnotationPresent(MSFiled.class)) {
    286. MSFiled annotation = field.getAnnotation(MSFiled.class);
    287. if (annotation.openFilter()) {
    288. filterKey.add(annotation.key());
    289. }
    290. if (annotation.openSort()) {
    291. sortKey.add(annotation.key());
    292. }
    293. if (annotation.noDisplayed()) {
    294. noDisPlay.add(annotation.key());
    295. }
    296. }
    297. }
    298. Results<Index> indexes = client.getIndexes();
    299. Index[] results = indexes.getResults();
    300. Boolean isHaveIndex = false;
    301. for (Index result : results) {
    302. if (uid.equals(result.getUid())) {
    303. isHaveIndex = true;
    304. break;
    305. }
    306. }
    307. if (isHaveIndex) {
    308. client.updateIndex(uid, primaryKey);
    309. } else {
    310. client.createIndex(uid, primaryKey);
    311. }
    312. this.index = client.getIndex(uid);
    313. Settings settings = new Settings();
    314. settings.setDisplayedAttributes(noDisPlay.size() > 0 ? noDisPlay.toArray(new String[noDisPlay.size()]) : new String[]{"*"});
    315. settings.setFilterableAttributes(filterKey.toArray(new String[filterKey.size()]));
    316. settings.setSortableAttributes(sortKey.toArray(new String[sortKey.size()]));
    317. index.updateSettings(settings);
    318. }
    319. }

    11、指定自动配置类所在

    12、项目有统一版本管理的设置下版本管理

    二、项目引用

    1、引入starter依赖(没有版本统一管理的要把version加上)

    2、基本使用

    2.1、建立索引(宽表)

    1. import cn.iocoder.yudao.framework.meilisearch.json.MSFiled;
    2. import cn.iocoder.yudao.framework.meilisearch.json.MSIndex;
    3. import lombok.AllArgsConstructor;
    4. import lombok.Builder;
    5. import lombok.Data;
    6. import lombok.NoArgsConstructor;
    7. @Data
    8. @Builder
    9. @AllArgsConstructor
    10. @NoArgsConstructor
    11. @MSIndex(uid = "com_baidu_main", primaryKey = "idToString")
    12. public class MainDO {
    13. private Long id;
    14. @MSFiled(openFilter = true, key = "idToString", openSort = true)
    15. private idToString;
    16. private String seedsName;
    17. @MSFiled(openFilter = true, key = "isDelete")
    18. private Integer isDelete;
    19. @MSFiled(openFilter = true, key = "status")
    20. private Integer status;
    21. @MSFiled(openFilter = true, key = "classFiledId")
    22. private Integer classFiledId;
    23. private String classFiledName;
    24. @MSFiled(openFilter = true, key = "tags")
    25. private List<TageInfo> tags;
    26. @MSFiled(openFilter = true,key = "createTime",openSort = true)
    27. @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'")
    28. private LocalDateTime createTime;
    29. @MSFiled(openFilter = true,key = "createTimeToLong",openSort = true)
    30. private LocalDateTime createTimeToLong;
    31. }

    2.2、集成starter里边的mapper对milisearch进行基本操作

    1. import cn.iocoder.yudao.framework.meilisearch.core.MeilisearchRepository;
    2. import org.springframework.stereotype.Repository;
    3. @Repository
    4. public class MeiliSearchMapper extends MeilisearchRepository {
    5. }

    2.3、当mongodb实现精准分页查询

    1. // 条件组装,实体类根据业务需要提前加好业务字段索引注解@MSFiled,显示隐藏 索引等
    2. StringBuffer sb = new StringBuffer();
    3. if (ObjectUtil.isNotEmpty(pageParam.getStartTime())) {
    4. sb.append("createTimeToLong>=").append(pageParam.getStartTime()).append(" AND ");
    5. }
    6. if (ObjectUtil.isNotEmpty(pageParam.getEndTime())) {
    7. sb.append("createTimeToLong<=").append(pageParam.getEndTime()).append(" AND ");
    8. }
    9. sb.append("userId=" + SecurityFrameworkUtils.getLoginUserId());
    10. // 分页查询及排序
    11. SearchRequest searchRequest4 = SearchRequest.builder()
    12. .sort(new String[]{"createTime:desc"})
    13. .page(pageParam.getPageNo())
    14. .hitsPerPage(pageParam.getPageSize())
    15. .filter(new String[]{sb.toString()}).build();
    16. SearchResult<SeedsDO> search = meiliSearchMapper.search(searchRequest4);
    17. return SeedCultivateConvert.INSTANCE.convert(search);
    18. // SeedCultivateConvert.INSTANCE.convert是个类转化器可手动转换成分页的统一数据格式
    19. pageResult.setList(search.getHits());
    20. pageResult.setTotal(search.getTotalPages());
    21. .......

    2.4、其他基本使用

    1. @Resource
    2. private MeiliSearchMapper meiliSearchMapper;
    3. //根据标签分页查询
    4. SearchRequest searchRequest4 = SearchRequest.builder()
    5. .limit(pageParam.getPageSize().intValue())
    6. .sort(new String[]{"createTime:desc"})
    7. .offset(pageParam.getPageNo().intValue() == 0 ? pageParam.getPageNo().intValue() : (pageParam.getPageNo().intValue() - 1) * pageParam.getPageSize().intValue())
    8. .filter(new String[]{"tags.id=" + "10010" + " AND status=1 AND isDelete=0"}).build();
    9. SearchResult<MainDO> search4 = meiliSearchMapper.search(searchRequest4);
    10. //保存Or编辑
    11. List<SeedsDO> articleCardDTOS = new ArrayList<>();
    12. Boolean aBoolean = meiliSearchMapper.add(articleCardDTOS) > 0 ? Boolean.TRUE : Boolean.FALSE;
    13. //按id删除
    14. meiliSearchMapper.delete(String.valueOf(10085));
    15. //根据类目分页查询
    16. SearchRequest searchRequest3 = SearchRequest.builder()
    17. .limit(pageParam.getPageSize().intValue())
    18. .offset(pageParam.getPageNo().intValue() == 0 ? pageParam.getPageNo().intValue() : (pageParam.getPageNo().intValue() - 1) * pageParam.getPageSize().intValue())
    19. .build();
    20. StringBuffer sb1 = new StringBuffer();
    21. sb.append("status =1 AND isDelete=0").append(" AND ").append("categoryId =").append(10086L);
    22. searchRequest.setFilter(new String[]{sb.toString()});
    23. searchRequest.setSort(new String[]{"createTime:desc"});
    24. SearchResult<SeedsDO> search3 = meiliSearchMapper.search(searchRequest3);

  • 相关阅读:
    【分布式】 A survey on the distributed computing stack论文小抄
    ESP32 ESP-IDF LVGL ST7789 演示lv_demo_music
    uniapp小程序中给web-view页面添加授权弹窗(使用cover-view组件覆盖实现该功能)
    经纬恒润再次荣获PACCAR集团 10PPM 质量奖
    gbk与utf8自动识别
    大数据项目之电商数仓、业务数据通道、Maxwell简介、Maxwell原理、MySQL主从复制读写分离、Maxwell部署
    概率论与数理统计---排列组合
    爬虫入门一
    C语言简易内存池实现
    Stirling-PDF:一款优秀的开源PDF处理工具
  • 原文地址:https://blog.csdn.net/qq_29653373/article/details/133179166