PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/solr/core/src/test/org/apache/solr/handler/component/CustomHighlightComponentTest.java

https://github.com/apache/solr
Java | 328 lines | 262 code | 28 blank | 38 comment | 32 complexity | d3764855220737731667e362c1002fc5 MD5 | raw file
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package org.apache.solr.handler.component;
  18. import java.lang.reflect.Array;
  19. import java.util.ArrayList;
  20. import java.util.HashSet;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.Set;
  24. import org.apache.solr.client.solrj.SolrQuery;
  25. import org.apache.solr.client.solrj.request.CollectionAdminRequest;
  26. import org.apache.solr.client.solrj.request.QueryRequest;
  27. import org.apache.solr.client.solrj.request.UpdateRequest;
  28. import org.apache.solr.client.solrj.response.QueryResponse;
  29. import org.apache.solr.cloud.AbstractDistribZkTestBase;
  30. import org.apache.solr.cloud.ConfigRequest;
  31. import org.apache.solr.cloud.SolrCloudTestCase;
  32. import org.apache.solr.common.util.NamedList;
  33. import org.apache.solr.common.util.SimpleOrderedMap;
  34. import org.apache.solr.highlight.SolrFragmentsBuilder;
  35. import org.junit.BeforeClass;
  36. import org.junit.Test;
  37. public class CustomHighlightComponentTest extends SolrCloudTestCase {
  38. public static class CustomHighlightComponent extends HighlightComponent {
  39. protected String id_key = "id";
  40. protected String snippets_key = "snippets";
  41. @Override
  42. protected String highlightingResponseField() {
  43. return "custom_highlighting";
  44. }
  45. @Override
  46. protected Object convertHighlights(NamedList<Object> hl) {
  47. final ArrayList<SimpleOrderedMap<Object>> hlMaps = new ArrayList<>();
  48. for (int i = 0; i < hl.size(); ++i) {
  49. SimpleOrderedMap<Object> hlMap = new SimpleOrderedMap<>();
  50. hlMap.add(id_key, hl.getName(i));
  51. hlMap.add(snippets_key, hl.getVal(i));
  52. hlMaps.add(hlMap);
  53. }
  54. return hlMaps;
  55. }
  56. @Override
  57. protected Object[] newHighlightsArray(int size) {
  58. return (SimpleOrderedMap<?>[]) Array.newInstance(SimpleOrderedMap.class, size);
  59. }
  60. @Override
  61. protected void addHighlights(Object[] objArr, Object obj, Map<Object, ShardDoc> resultIds) {
  62. SimpleOrderedMap<?>[] mapArr = (SimpleOrderedMap<?>[]) objArr;
  63. @SuppressWarnings("unchecked")
  64. final ArrayList<SimpleOrderedMap<?>> hlMaps = (ArrayList<SimpleOrderedMap<?>>) obj;
  65. for (SimpleOrderedMap<?> hlMap : hlMaps) {
  66. String id = (String) hlMap.get(id_key);
  67. ShardDoc sdoc = resultIds.get(id);
  68. int idx = sdoc.positionInResponse;
  69. mapArr[idx] = hlMap;
  70. }
  71. }
  72. @Override
  73. protected Object getAllHighlights(Object[] objArr) {
  74. final SimpleOrderedMap<?>[] mapArr = (SimpleOrderedMap<?>[]) objArr;
  75. // remove nulls in case not all docs were able to be retrieved
  76. ArrayList<SimpleOrderedMap<?>> mapList = new ArrayList<>();
  77. for (SimpleOrderedMap<?> map : mapArr) {
  78. if (map != null) {
  79. mapList.add(map);
  80. }
  81. }
  82. return mapList;
  83. }
  84. }
  85. protected String customHighlightComponentClassName() {
  86. return CustomHighlightComponent.class.getName();
  87. }
  88. protected String id_key = "id";
  89. protected String snippets_key = "snippets";
  90. private static String COLLECTION;
  91. @BeforeClass
  92. public static void setupCluster() throws Exception {
  93. // decide collection name ...
  94. COLLECTION = "collection" + (1 + random().nextInt(100));
  95. // ... and shard/replica/node numbers
  96. final int numShards = 3;
  97. final int numReplicas = 2;
  98. final int nodeCount = numShards * numReplicas;
  99. // create and configure cluster
  100. configureCluster(nodeCount).addConfig("conf", configset("cloud-dynamic")).configure();
  101. // create an empty collection
  102. CollectionAdminRequest.createCollection(COLLECTION, "conf", numShards, numReplicas)
  103. .processAndWait(cluster.getSolrClient(), DEFAULT_TIMEOUT);
  104. AbstractDistribZkTestBase.waitForRecoveriesToFinish(
  105. COLLECTION, cluster.getZkStateReader(), false, true, DEFAULT_TIMEOUT);
  106. }
  107. @Test
  108. public void test() throws Exception {
  109. // determine custom search handler name (the exact name should not matter)
  110. final String customSearchHandlerName = "/custom_select" + random().nextInt();
  111. final String defaultHighlightComponentName = HighlightComponent.COMPONENT_NAME;
  112. final String highlightComponentName;
  113. // add custom component (if needed) and handler
  114. {
  115. if (random().nextBoolean()) {
  116. // default component
  117. highlightComponentName = defaultHighlightComponentName;
  118. } else {
  119. // custom component
  120. highlightComponentName = "customhighlight" + random().nextInt();
  121. cluster
  122. .getSolrClient()
  123. .request(
  124. new ConfigRequest(
  125. "{\n"
  126. + " 'add-searchcomponent': {\n"
  127. + " 'name': '"
  128. + highlightComponentName
  129. + "',\n"
  130. + " 'class': '"
  131. + customHighlightComponentClassName()
  132. + "'\n"
  133. + " }\n"
  134. + "}"),
  135. COLLECTION);
  136. }
  137. // handler
  138. cluster
  139. .getSolrClient()
  140. .request(
  141. new ConfigRequest(
  142. "{\n"
  143. + " 'add-requesthandler': {\n"
  144. + " 'name' : '"
  145. + customSearchHandlerName
  146. + "',\n"
  147. + " 'class' : 'org.apache.solr.handler.component.SearchHandler',\n"
  148. + " 'components' : [ '"
  149. + QueryComponent.COMPONENT_NAME
  150. + "', '"
  151. + highlightComponentName
  152. + "' ]\n"
  153. + " }\n"
  154. + "}"),
  155. COLLECTION);
  156. }
  157. // add some documents
  158. final String id = "id";
  159. final String t1 = "a_t";
  160. final String t2 = "b_t";
  161. {
  162. new UpdateRequest()
  163. .add(sdoc(id, 1, t1, "bumble bee", t2, "bumble bee"))
  164. .add(sdoc(id, 2, t1, "honey bee", t2, "honey bee"))
  165. .add(sdoc(id, 3, t1, "solitary bee", t2, "solitary bee"))
  166. .commit(cluster.getSolrClient(), COLLECTION);
  167. }
  168. // search for the documents
  169. {
  170. // compose the query
  171. final SolrQuery solrQuery = new SolrQuery(t1 + ":bee");
  172. solrQuery.setRequestHandler(customSearchHandlerName);
  173. solrQuery.setHighlight(true);
  174. final boolean t1Highlights = random().nextBoolean();
  175. if (t1Highlights) {
  176. solrQuery.addHighlightField(t1);
  177. }
  178. final boolean t2Highlights = random().nextBoolean();
  179. if (t2Highlights) {
  180. solrQuery.addHighlightField(t2);
  181. }
  182. // make the query
  183. final QueryResponse queryResponse =
  184. new QueryRequest(solrQuery).process(cluster.getSolrClient(), COLLECTION);
  185. // analyse the response
  186. final Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting();
  187. @SuppressWarnings({"unchecked"})
  188. final ArrayList<SimpleOrderedMap<Object>> custom_highlighting =
  189. (ArrayList<SimpleOrderedMap<Object>>)
  190. queryResponse.getResponse().get("custom_highlighting");
  191. if (defaultHighlightComponentName.equals(highlightComponentName)) {
  192. // regular 'highlighting' ...
  193. if (t1Highlights) {
  194. checkHighlightingResponseMap(highlighting, t1);
  195. }
  196. if (t2Highlights) {
  197. checkHighlightingResponseMap(highlighting, t2);
  198. }
  199. if (!t1Highlights && !t2Highlights) {
  200. checkHighlightingResponseMap(highlighting, null);
  201. }
  202. // ... and no 'custom_highlighting'
  203. assertNull(custom_highlighting);
  204. } else {
  205. // no regular 'highlighting' ...
  206. assertNull(highlighting);
  207. // ... but 'custom_highlighting'
  208. assertNotNull(custom_highlighting);
  209. if (t1Highlights) {
  210. checkHighlightingResponseList(custom_highlighting, t1);
  211. }
  212. if (t2Highlights) {
  213. checkHighlightingResponseList(custom_highlighting, t2);
  214. }
  215. if (!t1Highlights && !t2Highlights) {
  216. checkHighlightingResponseList(custom_highlighting, null);
  217. }
  218. }
  219. }
  220. }
  221. protected void checkHighlightingResponseMap(
  222. Map<String, Map<String, List<String>>> highlightingMap, String highlightedField) {
  223. assertEquals(
  224. "too few or too many keys: " + highlightingMap.keySet(), 3, highlightingMap.size());
  225. checkHighlightingResponseMapElement(
  226. highlightingMap.get("1"), highlightedField, "bumble ", "bee");
  227. checkHighlightingResponseMapElement(
  228. highlightingMap.get("2"), highlightedField, "honey ", "bee");
  229. checkHighlightingResponseMapElement(
  230. highlightingMap.get("3"), highlightedField, "solitary ", "bee");
  231. }
  232. protected void checkHighlightingResponseMapElement(
  233. Map<String, List<String>> docHighlights,
  234. String highlightedField,
  235. String preHighlightText,
  236. String highlightedText) {
  237. if (highlightedField == null) {
  238. assertEquals(0, docHighlights.size());
  239. } else {
  240. List<String> docHighlightsList = docHighlights.get(highlightedField);
  241. assertEquals(1, docHighlightsList.size());
  242. assertEquals(
  243. preHighlightText
  244. + SolrFragmentsBuilder.DEFAULT_PRE_TAGS
  245. + highlightedText
  246. + SolrFragmentsBuilder.DEFAULT_POST_TAGS,
  247. docHighlightsList.get(0));
  248. }
  249. }
  250. protected void checkHighlightingResponseList(
  251. ArrayList<SimpleOrderedMap<Object>> highlightingList, String highlightedField) {
  252. assertEquals(
  253. "too few or too many elements: " + highlightingList.size(), 3, highlightingList.size());
  254. final Set<String> seenDocIds = new HashSet<>();
  255. for (SimpleOrderedMap<Object> highlightingListElementMap : highlightingList) {
  256. final String expectedHighlightText;
  257. final String actualHighlightText;
  258. // two elements in total: id and snippets
  259. assertEquals(highlightingList.toString(), 2, highlightingListElementMap.size());
  260. // id element
  261. {
  262. final String docId = (String) highlightingListElementMap.get(id_key);
  263. seenDocIds.add(docId);
  264. final String preHighlightText;
  265. final String highlightedText = "bee";
  266. if ("1".equals(docId)) {
  267. preHighlightText = "bumble ";
  268. } else if ("2".equals(docId)) {
  269. preHighlightText = "honey ";
  270. } else if ("3".equals(docId)) {
  271. preHighlightText = "solitary ";
  272. } else {
  273. preHighlightText = null;
  274. fail("unknown docId " + docId);
  275. }
  276. expectedHighlightText =
  277. preHighlightText
  278. + SolrFragmentsBuilder.DEFAULT_PRE_TAGS
  279. + highlightedText
  280. + SolrFragmentsBuilder.DEFAULT_POST_TAGS;
  281. }
  282. // snippets element
  283. {
  284. @SuppressWarnings({"unchecked"})
  285. SimpleOrderedMap<Object> snippets =
  286. (SimpleOrderedMap<Object>) highlightingListElementMap.get(snippets_key);
  287. if (highlightedField == null) {
  288. assertEquals(0, snippets.size());
  289. } else {
  290. @SuppressWarnings({"unchecked"})
  291. ArrayList<String> docHighlights = (ArrayList<String>) (snippets).get(highlightedField);
  292. assertEquals(1, docHighlights.size());
  293. actualHighlightText = docHighlights.get(0);
  294. assertEquals(expectedHighlightText, actualHighlightText);
  295. }
  296. }
  297. }
  298. assertEquals(3, seenDocIds.size());
  299. }
  300. }