H2 的全文檢索功能

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在前面的文章中,我們介紹了 "},{"type":"link","attrs":{"href":"https://zhuanlan.zhihu.com/p/142758091","title":null},"content":[{"type":"text","text":"H2 的一些特性"}]},{"type":"text","text":"以及 "},{"type":"link","attrs":{"href":"https://zhuanlan.zhihu.com/p/142754824","title":null},"content":[{"type":"text","text":"爲什麼H2 適合應用在測試環境中"}]},{"type":"text","text":"。H2 不但可以作爲嵌入式數據庫、內存數據庫使用。在適當的場景下可以選擇使用 H2 替換掉 SQLite,還可利用 H2 內存數據庫的特點,將它還提供了全文檢索的功能。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"H2 內置了兩個全文檢索(FullText Search)的實現:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"Native FullText Search。"},{"type":"text","text":"使用 H2 中內置的全文檢索,將索引存儲在數據庫指定的表中。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"Apache Lucene FullText Search。"},{"type":"text","text":" H2 使用 Java 來進行變得,因此可以依賴第三方庫來實現功能的擴展,在"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1 命令行中使用 Native FullText Search"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面的例子中有主要涉及到兩個表:Car(汽車)、Brand(廠商),其中涉及到一些關鍵詞兩個表中都涉及到,通過全文檢索能夠快速定位到數據在這兩表中的位置。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1.1 創建表"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"創建 cars 和 brands 的表結構。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"sql"},"content":[{"type":"text","text":"create SCHEMA TEST_SCHEMA;\n\ncreate table TEST_SCHEMA.cars\n(\n id bigint generated always as identity not null,\n name varchar(20),\n introduce varchar(200),\n primary key (id)\n);\n\n\ncreate table TEST_SCHEMA.brands\n(\n id bigint generated always as identity not null,\n name varchar(20),\n primary key (id)\n);"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"創建後如下圖:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/98/98789fd6451ad54084388afb2543189d.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1.2 創建索引"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用 FT_INIT() 來進行全文檢索的初始化,初始化過程指定使用 H2 內置的全文檢索功能。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"sql"},"content":[{"type":"text","text":"create alias if not exists FT_INIT for \"org.h2.fulltext.FullText.init\";\n\nCALL FT_INIT();"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"執行完語句之後會創建名字爲 "},{"type":"codeinline","content":[{"type":"text","text":"FT"}]},{"type":"text","text":" 的 Schema,在 FT 中會創建幾個新的表,其中 "},{"type":"codeinline","content":[{"type":"text","text":"INDEXS"}]},{"type":"text","text":" 中存儲的是建立索引的規則。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/57/577c163bdbb23bdb20dde7bf5766c7e7.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"指定建立索引的表和列。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"sql"},"content":[{"type":"text","text":"CALL FT_CREATE_INDEX('TEST_SCHEMA', 'CARS', NULL);\nCALL FT_CREATE_INDEX('TEST_SCHEMA', 'BRANDS', NULL);"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"FT_CREATE_INDEX"}]},{"type":"text","text":" 函數的"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​ 第一個參數指定的建立索引的 SCHEMA Name;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​ 第二個參數是建立索引的 TABLE Name;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​ 第三個參數是建立索引的列表,當爲 NULL 時表示爲所有列建立索引。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/df/df40f0954c57747365236e862599ad11.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1.3 插入數據並查詢索引"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"sql"},"content":[{"type":"text","text":"insert into TEST_SCHEMA.cars values (1, 'benz A200', 'Benz A200 L Car'), (2, 'BMW 3', 'BMW 3 2.0L');\n\ninsert into TEST_SCHEMA.brands values (1, 'benz'), (2, 'BMW');"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"插入數據後,結構如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c2/c2cfac35e9172e69440230595aa76cb8.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"搜索之前我們先確定要得到的結果,通過上圖,我們知道,包含關鍵字 benz 的關鍵字記錄一共 有兩條。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"cars 表中的 id 爲 1 的記錄,出現在 name、introduce 兩列中,"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"brands 表中 id 爲 1 的記錄,出現在 name 列中。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"查詢關鍵字 "},{"type":"codeinline","content":[{"type":"text","text":"benz"}]},{"type":"text","text":" 應該得到 2 條記錄;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"sql"},"content":[{"type":"text","text":"SELECT * FROM FT_SEARCH_DATA('benz', 0, 0);"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"搜索結果包含 5 個字段:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​ "},{"type":"text","marks":[{"type":"strong"}],"text":"SCHEMA"},{"type":"text","text":": 搜索到的記錄所屬的 Schema 名稱;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​ "},{"type":"text","marks":[{"type":"strong"}],"text":"TABLE"},{"type":"text","text":": 搜索到的記錄所屬的 table 名稱"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​ "},{"type":"text","marks":[{"type":"strong"}],"text":"COLUMNS"},{"type":"text","text":": 搜索到的結果定位的 column 名"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​ "},{"type":"text","marks":[{"type":"strong"}],"text":"KEYS"},{"type":"text","text":": 搜索到的結果記錄對應的地址"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​ "},{"type":"text","marks":[{"type":"strong"}],"text":"SCORE"},{"type":"text","text":": 搜索到的結果評分,在 H2 的 Native FullText Search 中 score 的值始終爲 1.0"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"查詢結果如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a5/a5bd5ad2ac44834ffa53f492337045df.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另外搜索的結果是忽略大小寫的,一次搜索 "},{"type":"codeinline","content":[{"type":"text","text":"BENZ"}]},{"type":"text","text":" 會得到的同樣的搜索結果。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"經過嘗試,H2 內置的全文檢索是按照英文字符進行分詞的,數字和字母分詞,如果是中文依然按照英文字符進行分詞。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"例如:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"\"馬自達,創馳藍天\" 分詞後爲 \"馬自達,創馳藍天\""}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"\"創馳藍天,2.5L\" 分詞後爲\"創馳藍天\",\"2\",\"5\",\"L\",\"創馳藍天,2\",創馳藍天,2.5\",\"創馳藍天,2.5L\", \"2.5\", \"5L\", \"2.5\"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"瞭解分詞之後規則之後,在一些簡單的場景中就可以使用這種簡單的全文檢索功能。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1.4 刪除索引"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"sql"},"content":[{"type":"text","text":"# 刪除指定的庫\ncall FT_DROP('TEST_SCHEMA', 'CARS');\n\n# 刪除全部索引\ncall FT_DROP_ALL();"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2 Java 代碼中使用 H2 的全文檢索功能"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Spring Boot 2.x 中使用的數據庫連接池爲 HikariCP,"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"application.properties"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"spring.datasource.schema=schema.sql\nspring.datasource.data=data.sql\nspring.datasource.type=org.h2.jdbcx.JdbcDataSource\n\nspring.jpa.show-sql=true\nspring.jpa.hibernate.ddl-auto=update"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"schema.sql"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"sql"},"content":[{"type":"text","text":"create table cars\n(\n id bigint generated always as identity not null,\n name varchar(20),\n introduce varchar(200),\n primary key (id)\n);\n\n\ncreate table brands\n(\n id bigint generated always as identity not null,\n name varchar(20),\n primary key (id)\n);\n\n\n# 使用 H2 Native FullText Search 初始化\ncreate alias if not exists FT_INIT for \"org.h2.fulltext.FullText.init\";\nCALL FT_INIT();\n\n# 創建索引\nCALL FT_CREATE_INDEX('PUBLIC', 'CARS', NULL);\nCALL FT_CREATE_INDEX('PUBLIC', 'BRANDS', NULL);"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"data.sql"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"sql"},"content":[{"type":"text","text":"insert into cars values (1, 'benz A200', 'Benz A200 L Car'), (2, 'BMW 3', 'BMW 3 2.0L');\n\ninsert into brands values (1, 'benz'), (2, 'BMW');"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"測試代碼"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@SpringBootTest\nclass FullTextSearchTests {\n\n @Autowired\n private FullTextService fullTextService;\n\n @Test\n void should_got_2_record_when_fulltext_search_given_2_cars_records_and_2_brands_records() throws SQLException {\n List results = fullTextService.search(\"benz\");\n\n then(results.size()).isEqualTo(2);\n }\n\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其他依賴的類:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Brand.java"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Data\n@Entity\n@Table(name = \"brands\")\npublic class Brand {\n\n @Id\n @GeneratedValue(strategy = GenerationType.IDENTITY)\n private long id;\n\n private String name;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Car.java"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Data\n@Entity\n@Table(name = \"cars\")\npublic class Car {\n @Id\n @GeneratedValue(strategy = GenerationType.IDENTITY)\n private long id;\n\n private String name;\n\n private String introduce;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"BrandRepository.java"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Repository\npublic interface BrandRepository extends JpaRepository {\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"CarRepository.java"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Repository\npublic interface CarRepository extends JpaRepository {\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"FullTextSearchResult.java 將全文檢索搜索結果封裝爲該類。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Builder\n@Data\npublic class FullTextSearchResult {\n\n private String schema;\n\n private String table;\n\n private String columns;\n\n private String keys;\n\n private BigDecimal score;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"FullTextService.java"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Service\npublic class FullTextService {\n\n public static final int SEARCH_RESULT_LIMIT = 0;\n public static final int SEARCH_RESULT_OFFSET = 0;\n\n public static final int SCHEMA_INDEX = 1;\n public static final int TABLE_INDEX = 2;\n public static final int COLUMNS_INDEX = 3;\n public static final int KEYS_INDEX = 4;\n public static final int SCORE_INDEX = 5;\n\n\n @Autowired\n private DataSource dataSource;\n\n public List search(String keyword) throws SQLException {\n List results = new ArrayList<>();\n\n ResultSet resultSet = FullText.searchData(\n dataSource.getConnection(),\n keyword,\n SEARCH_RESULT_LIMIT,\n SEARCH_RESULT_OFFSET);\n while (resultSet.next()) {\n String schemaName = resultSet.getString(SCHEMA_INDEX);\n String tableName = resultSet.getString(TABLE_INDEX);\n Object[] columns = (Object[]) resultSet.getArray(COLUMNS_INDEX).getArray();\n String column = (String) columns[0];\n Object[] keys = (Object[]) resultSet.getArray(KEYS_INDEX).getArray();\n String key = (String) keys[0];\n BigDecimal score = resultSet.getBigDecimal(SCORE_INDEX);\n\n results.add(\n FullTextSearchResult.builder()\n .schema(schemaName)\n .table(tableName)\n .columns(column)\n .keys(key)\n .score(score)\n .build());\n }\n\n return results;\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在提取全文檢索的結果時 H2 提供的類並不能方便的使用。因此可以添加 FullText 的代理類,將常用的方法進行封裝。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3 使用 Apache Lucene 的全文檢索"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由於 H2 是使用 Java 編寫的,因此只需要引入 Apache Lucene 的類,即可進行數據庫的擴展。與Native FullText Search 不同,使用 Apache Lucene 會講索引儲存在 Lucene 之中,並可以根據 Lucene 提供的特性進行分詞和索引的功能擴展。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另外當前最新版本的 H2 數據庫支持 Apache Lucene 5.5 以及 8.0.x 版本。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.1 命令行中使用 Apache Lucene 創建索引"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"初始化使用:org.h2.fulltext.FullTextLucene.init"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"sql"},"content":[{"type":"text","text":"create alias if not exists FTL_INIT for \"org.h2.fulltext.FullTextLucene.init\";\nCALL FTL_INIT();"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其他操作均以 FTL_ 開頭的函數來進行操作,例如: FTL_SEARCH_DATA()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.2 H2 提供的了對 Apahce Lucene 操作的封裝類"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以使用 "},{"type":"codeinline","content":[{"type":"text","text":"fulltext.FullTextLucene.searchData"}]},{"type":"text","text":" 類進行數據的檢索。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"更多 API 可參考"},{"type":"link","attrs":{"href":"https://link.zhihu.com/?target=http%3A//www.h2database.com/javadoc/index.html","title":null},"content":[{"type":"text","text":"H2 Database Java doc"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章