Liferay6.1和6.0比,那是灵活性提高了太多。

可以在hook里面适当改改就封装多比较好的功能。下面介绍一下全文检索。

内容来自:http://www.liferay.com/ja/web/raymond.auge/blog/-/blogs/faceted-search-in-liferay-6-1

  1. Advanced operations: These are supported directly in the search input box. Most of the advanced operations supported by Lucene are supported with only slight variations.

    For a full description of the Lucene syntax see: http://lucene.apache.org/core/old_versioned_docs/versions/3_0_3/queryparsersyntax.html

    Note: Many of the descriptions bellow are copied (almost word for word) from the above reference to account for the similarities but also to highlight the slight variations found between the two.

    • Searching in specific fields: By default, searches are performed against a long list of fields (this is different from Lucene which searches a single specific field by default). Sometimes you want results for a term within a particular field. This can be achieved using the field search syntax:

      <field>:<term> title:liferay

      Searching for a phrase within a field requires surrounding the term with double quotation marks:

      content:"Create categories"

      Note:The field is only valid for the term that it directly precedes, so the query

      content:Create categories will search for the term "Create" in the content field, and the term "categories" will be searched in "all" the default fields.

    • Wildcard Searches: The Search Portlet supports single and multiple character wildcard searches within single terms not within phrase queries.

      To perform a single character wildcard search use the "?" symbol.

      To perform a multiple character wildcard search use the "*" symbol.

      The single character wildcard search looks for terms that match that with the single character replaced. For example, to search for "text" or "test" you can use the search:

      te?t Multiple character wildcard searches looks for 0 or more characters. For example, to search for test, tests or tester, you can use the search:

      test* You can also use the wildcard searches in the middle of a term.

      te*t Note: You cannot use a "*" or "?" symbol as the first character of a search.

    • Fuzzy Searches : Search supports fuzzy searches based on the Levenshtein Distance, or Edit Distance algorithm. To do a fuzzy search use the tilde, "~", symbol at the end of a single word term.

      For example to search for a term similar in spelling to "roam" use the fuzzy search:

      roam~ This search will find terms like foam and roams.

      An additional (optional) parameter can specify the required similarity. The value is between 0 and 1, with a value closer to 1 only terms with a higher similarity will be matched. For example:

      roam~0.8 The default that is used if the parameter is not given is 0.5.

    • Range Searches: Ranges allow one to match documents whose field(s) values are between the lower and upper bound specified by the range. Ranges can be inclusive or exclusive of the upper and lower bounds. Sorting is done lexicographically.

      modified:[20020101000000 TO 20030101000000] This will find documents whose modified fields have values between 2002/01/01 and 2003/01/01, inclusive.

      Note: Liferay's date fields are always formatted according to the value of the propertyindex.date.format.pattern. The format used should be a sortable pattern. The default date format pattern used isyyyyMMddHHmmss. So, when comparing or searching by dates, this format must be used.

      You can also use ranges with non-date fields:

      title:{Aida TO Carmen} This will find all documents whose titles are between Aida and Carmen, but not including Aida and Carmen.

      Inclusive range queries are denoted by square brackets. Exclusive range queries are denoted by curly brackets.

      Note: Ranges can only be applied to single value fields.

    • Boolean Operators: Boolean operators allow terms to be combined through logical operations. The Search Portlet supports AND, "+", OR, NOT and "-" as Boolean operators.

      Note: Boolean operators must be ALL CAPS.

      • The OR operator is the default conjunction operator. This means that if there is no Boolean operator between two terms, the OR operator is used. The OR operator links two terms and finds a matching document if either of the terms exist in a document. This is equivalent to a union using sets. The symbol || can be used in place of the word OR.

        To search for documents that contain either "liferay portal" or just "liferay" use the query:

        "liferay portal" liferay or

        "liferay portal" OR liferay

      • The AND operator matches documents where both terms exist anywhere in the text of a single document. This is equivalent to an intersection using sets. The symbol&& can be used in place of the word AND.

        To search for documents that contain "liferay portal" and "Apache Lucene" use the query:

        "liferay portal" AND "Apache Lucene"

      • The "+" or required operator requires that the term after the "+" symbol exist somewhere in a field of a single document.

        To search for documents that must contain "liferay" and may contain "lucene" use the query:

        +liferay lucene

      • The NOT operator excludes documents that contain the term after NOT. This is equivalent to a difference using sets. The symbol! can be used in place of the word NOT.

        To search for documents that contain "liferay portal" but not "Apache Lucene" use the query:

        "liferay portal" NOT "Apache Lucene" Note: The NOT operator cannot be used with just one term. For example,the following search will return no results:

        NOT "liferay portal"

      • The "-" or prohibit operator excludes documents that contain the term after the "-" symbol.

        To search for documents that contain "liferay portal" but not "Apache Lucene" use the query:

        "liferay portal" -"Apache Lucene"

    • Grouping: Search supports using parentheses to group clauses to form sub queries. This can be very useful if you want to control the boolean logic for a query.

      To search for either "liferay" or "apache" and "website" use the query:

      (liferay OR apache) AND website This eliminates any confusion and makes sure that website must exist and either term liferay or apache may exist.

    • Field Grouping: Search supports using parentheses to group multiple clauses to a single field.

      To search for a title that contains both the word "return" and the phrase "pink panther" use the query:

      title:(+return +"pink panther")

    • Proximity Searches and Term Boosting are not supported.

Portlet Configuration

[Updated: Oct 16 2012] Search portlet configurations are currently scoped to thesite page, which means that all Search Portletsused in the same site will have the same settings, regardless of their location or positionon different pages will have their own configurations; this also includes any instances of the portlet embedded in themes, or other templates.

Display Settings:

  • Basic : This represents the most basic way of controlling the visible facets.

    Display Asset Type Facet: Display or not.
    Display Asset Tags Facet: Display or not.
    Display Asset Categories Facet: Display or not.
    Display Modified Range Facet: Display or not.

  • Advanced: This mode gives ultimate control over the display of facets and is where the true power lies in the Search Portlet. However, it is not for the faint of heart and requires creating a configuration inJSON format. (Future versions of Liferay will include a user friendly user interface for configuration of facets.)

    In it's default configuration, the Search Portlet configuration would equate to the following JSON text:

    {"facets": [{"className": "com.liferay.portal.kernel.search.facet.AssetEntriesFacet","data": {"frequencyThreshold": 1,"values": ["com.liferay.portlet.bookmarks.model.BookmarksEntry","com.liferay.portlet.blogs.model.BlogsEntry","com.liferay.portlet.calendar.model.CalEvent","com.liferay.portlet.documentlibrary.model.DLFileEntry","com.liferay.portlet.journal.model.JournalArticle","com.liferay.portlet.messageboards.model.MBMessage","com.liferay.portlet.wiki.model.WikiPage","com.liferay.portal.model.User"]},"displayStyle": "asset_entries","fieldName": "entryClassName","label": "asset-type","order": "OrderHitsDesc","static": false,"weight": 1.5},{"className": "com.liferay.portal.kernel.search.facet.MultiValueFacet","data": {"maxTerms": 10,"displayStyle": "list","frequencyThreshold": 1,"showAssetCount": true},"displayStyle": "asset_tags","fieldName": "assetTagNames","label": "tag","order": "OrderHitsDesc","static": false,"weight": 1.4},{"className": "com.liferay.portal.kernel.search.facet.MultiValueFacet","data": {"maxTerms": 10,"displayStyle": "list","frequencyThreshold": 1,"showAssetCount": true},"displayStyle": "asset_tags","fieldName": "assetCategoryTitles","label": "category","order": "OrderHitsDesc","static": false,"weight": 1.3},{"className": "com.liferay.portal.kernel.search.facet.ModifiedFacet","data": {"ranges": [{"range": "[past-hour TO *]","label": "past-hour"},{"range": "[past-24-hours TO *]","label": "past-24-hours"},{"range": "[past-week TO *]","label": "past-week"},{"range": "[past-month TO *]","label": "past-month"},{"range": "[past-year TO *]","label": "past-year"}],"frequencyThreshold": 0},"displayStyle": "modified","fieldName": "modified", "label": "modified","order": "OrderHitsDesc","static": false,"weight": 1.1}
    ]}
    

    The base definition consists of a JSON object with a field of type array named "facets":

    {"facets": []}

    This array must contain elements (which in JSON are called Objects) having the following mandatory structure:

    {"className": ...,"data": ...,"displayStyle": ...,"fieldName": ...,"label": ...,"order": ...,"static": ...,"weight": ...
    }
    
    • "className": This field must contain a string value which is the FQCN (fully qualified class name) of a java implementation class implementing the Facet interface. Liferay provides the following implementations by default:

      "com.liferay.portal.kernel.search.facet.AssetEntriesFacet"
      "com.liferay.portal.kernel.search.facet.ModifiedFacet"
      "com.liferay.portal.kernel.search.facet.MultiValueFacet"
      "com.liferay.portal.kernel.search.facet.RangeFacet"
      "com.liferay.portal.kernel.search.facet.ScopeFacet"
      "com.liferay.portal.kernel.search.facet.SimpleFacet"
      
    • "data": This field takes an arbitrary JSON "Object" (a.k.a. {}) for use by a specific facet implementation. As such, there is no fixed definition of the data field. Each implementation is free to structure it as needed.
    • "displayStyle": This field takes a value of type string and represents a particular template implementation which is used to render the facet. These templates are normally JSP pages (but can also be implemented as Velocity or Freemarker templates provided by a theme if the portal property theme.jsp.override.enabled is set to true). The method of matching the string to a JSP is simply done by prefixing the string with /html/portlet/search/facets/ and appending the .jsp extension.

      e.g. "displayStyle": "asset_tags"

      maps to the JSP

      /html/portlet/search/facets/asset_tags.jsp Armed with this knowledge a crafty developer could create custom display styles by deploying custom (new or overriding) JSPs using a JSP hook.

    • "fieldName": This field takes a string value and indicates the indexed field on which the facet will operate.

      e.g. "fieldName": "entryClassName"

      indicates that the specified facet implementation will operate on the entryClassName indexed field.

      Note: You can identify available indexed fields by checkmarking the Search Portlet'sDisplay Results in Document Form configuration setting and then expanding individual results by clicking the[+] to the left of their title.

    • "label": This field takes a string value and represents the language key that will be used for localizing the title of the facet when rendered.
    • "order": This field takes a string value. There are two possible values:

      "OrderValueAsc" This tells the facet to sort it's results by the term values, in ascending order.

      "OrderHitsDesc" This tells the facet to sort it's results by the term frequency, in descending order.

    • "static": This field takes a boolean value (true orfalse). A value of true means that the facet should not actually be rendered in the UI. It also means that, rather than using inputs dynamically applied by the end user, it should use pre-set values (stored in it's "data" field). This allows for the creation of pre-configured result domain. The default value is false.

      Image Search Example: Imagine you would like to create a pre-configured search that returns only images (i.e. the indexed field "entryClassName" would be com.liferay.portlet.documentlibrary.model.DLFileEntry and the indexed field "extension" should contain one of bmp, gif, jpeg, jpg, odg, png, or svg). We would need two static facets, one with"fieldName": "entryClassName" and another with "fieldName": "extension". This could be represented using the following facet configuration:

      {"displayStyle": "asset_entries","static": true,"weight": 1.5,"order": "OrderHitsDesc","data": {"values": ["com.liferay.portlet.documentlibrary.model.DLFileEntry"],"frequencyThreshold": 0},"className": "com.liferay.portal.kernel.search.facet.AssetEntriesFacet","label": "asset-type","fieldName": "entryClassName"
      },
      {"displayStyle": "asset_entries","static": true,"weight": 1.5,"order": "OrderHitsDesc","data": {"values": ["bmp", "gif", "jpeg", "jpg", "odg", "png", "svg"],"frequencyThreshold": 0},"className": "com.liferay.portal.kernel.search.facet.MultiValueFacet","label": "images","fieldName": "extension"
      }
      
                  
    • "weight": This field takes a floating point (or double) value and is used to determine the ordering of the facets in the facet column of the search portlet. Facets are positioned with the largest values at the top (yes it's counter intuitive and perhaps should be reversed in future versions).

Other Settings

  • Display Results in Document Form: This configuration, if checked, will display each result with an expendable section you can reach by clicking the [+] to the left of the result's title. In Document Form, all of the result's indexed fields will be shown in the expandable section. This is for use in testing search behavior.

    Note: Even if enabled, for security reasons this ability is only available to the portal Administrator role because the raw contents of the index may expose protected information.

  • View in Context: This configuration, if checked, will produce results which have links that target the first identifiable application to which the result is native.

    For example, a Blog entry title will link (or attempt to link) to a Blogs Admin, Blogs, or Blogs Aggregator portlet somewhere in the current site. The exact method of location is defined by the result type's AssetRenderer implementation.

  • Display Main Query: This configuration, if checked, will output the complete query that was used to perform the search. This will appear directly bellow the result area, like this:

  • Display Open Search Results: In previous versions of the portal, the Search Portlet was implemented as a collection of com.liferay.portal.kernel.search.OpenSearch implementation classes which were executed in series. Due to the subsequent re-design of the Search Portlet, the portal itself no longer relies on these implementations for it's primary search. However, third party plugin developers may yet have Open Search implementations which they would like to continue to use. This configuration, if checked, will enable the execution of these third party Open Search implementations and results will appear bellow the primary portal search.

    Note: It is highly recommended that third parties re-design their search code to implementcom.liferay.portal.kernel.search.Indexer or more simply to extend com.liferay.portal.kernel.search.BaseIndexer. Thus it will be possible to aggregate custom assets with native portal assets.

For Developers

Key Classes

When implementing a customized search, many of following API classes are important:

com.liferay.portal.kernel.search.SearchContext
com.liferay.portal.kernel.search.SearchContextFactory
com.liferay.portal.kernel.search.facet.config.FacetConfiguration
com.liferay.portal.kernel.search.facet.config.FacetConfigurationUtil
com.liferay.portal.kernel.search.facet.util.FacetFactoryUtil
com.liferay.portal.kernel.search.facet.Facet
com.liferay.portal.kernel.search.Indexer
com.liferay.portal.kernel.search.IndexerRegistryUtil
com.liferay.portal.kernel.search.BaseIndexer
com.liferay.portal.kernel.search.FacetedSearcher
com.liferay.portal.kernel.search.SearchEngineUtil
com.liferay.portal.kernel.search.Hits
com.liferay.portal.kernel.search.Document
com.liferay.portal.kernel.search.facet.collector.FacetCollector
com.liferay.portal.kernel.search.facet.collector.TermCollector

We'll briefly go through the general organization of the above to understand where each class fits into the greater scheme.

SearchContext

The first thing required is to setup a context within which to perform a search. The context defines things like company instance to search, the current user invoking the search, etc. This task is handled by thecom.liferay.portal.kernel.search.SearchContext class. Since this class has a wide variety of context properties to deal with, the most effective way to get one is to call thegetInstance(HttpServletRequest request) method of the com.liferay.portal.kernel.search.SearchContextFactory class.

SearchContext searchContext = SearchContextFactory.getInstance(request);

Context Properties

Once you have a SearchContext instance, we then can populate values like the pagination style, start and end:

searchContext.setAttribute("paginationType", "more");
searchContext.setEnd(mainSearchSearchContainer.getEnd());
searchContext.setStart(mainSearchSearchContainer.getStart());

There are number of other SearchContext properties that can be set. See the javadocs for a complete list.

Setting up Facets

After we have setup all the appropriate SearchContext properties, we are ready to add the Facets for which we want to collect information. We can add Facets either programatically or through configuration. Programatically adding facets allows the developer to tightly control how the search is used. The following example shows how to add two facets using some provided Facet classes:

Facet assetEntriesFacet = new AssetEntriesFacet(searchContext);
assetEntriesFacet.setStatic(true);
searchContext.addFacet(assetEntriesFacet);Facet scopeFacet = new ScopeFacet(searchContext);
scopeFacet.setStatic(true);
searchContext.addFacet(scopeFacet);

Note: The above two Facet implementations are not re-usable in that they always operate on specific indexed fields; entryClassName, and groupId (and scopeGroupId) respectively. Other implementations can be re-used with any index fields as demonstrated previously in the Image Search Example.

As shown previously, facets can also be setup using a JSON definition. Using a JSON definition allows for the highest level of flexibility since the configuration can be changed at run-time. These definitions are parsed by the static methodload(String configuration) on the com.liferay.portal.kernel.search.facet.config.FacetConfigurationUtil class. This method reads the JSON text and returns a list ofcom.liferay.portal.kernel.search.facet.config.FacetConfiguration instances.

List<FacetConfiguration> facetConfigurations = FacetConfigurationUtil.load(searchConfiguration);for (FacetConfiguration facetConfiguration : facetConfigurations) {Facet facet = FacetFactoryUtil.create(searchContext, facetConfiguration);searchContext.addFacet(facet);
}

Facets as Filters

It should be noted that Facets are always created with reference to the SearchContext. Since facets also behave as the dynamic filter mechanism for narrowing search results, having the SearchContext allows a Facet implementation to observe and react to context changes such as looking for specific parameters which affect it's behavior.

Indexer Implementations

The next step involves obtaining a reference to an indexer implementation. The implementation obtained determines the type of results return from the search.

With respect to searching, there are two categories of Indexer implementations:Asset Specific Searchers and Aggregate Searchers.

Asset Specific Searchers

As the name implies, Asset Specific Searchers always deal with only one specific type of asset. These are the implementations that are provided by developers when creating/designing custom Asset types. Liferay provides the following Asset Specific Searchers:

com.liferay.portal.plugin.PluginPackageIndexer
com.liferay.portlet.blogs.util.BlogsIndexer
com.liferay.portlet.bookmarks.util.BookmarksIndexer
com.liferay.portlet.calendar.util.CalIndexer
com.liferay.portlet.documentlibrary.util.DLIndexer
com.liferay.portlet.journal.util.JournalIndexer
com.liferay.portlet.messageboards.util.MBIndexer
com.liferay.portlet.softwarecatalog.util.SCIndexer
com.liferay.portlet.usersadmin.util.OrganizationIndexer
com.liferay.portlet.usersadmin.util.UserIndexer
com.liferay.portlet.wiki.util.WikiIndexer

A developer tells the portal about Indexer implementations by declaring them in their liferay-portlet.xml file.

<indexer-class>com.liferay.portlet.calendar.util.CalIndexer</indexer-class>

Any number of such implementations may be provided.

Aggregate Searchers

Obtaining a reference to an Asset Specific Indexer requires calling either thegetIndexer(Class<?> clazz) or getIndexer(String className) methods on thecom.liferay.portal.kernel.search.IndexerRegistryUtil class.

Indexer indexer = IndexerRegistryUtil.getIndexer(PluginPackage.class);

Aggregate Searchers can return any of the asset types in the index according to the SearchContext and/or facet configuration. Liferay only provides a single aggregate searcher implementation:

com.liferay.portal.kernel.search.FacetedSearcher

Obtaining a reference to this searcher simply involves calling the static getInstance() method of the same class.

Indexer indexer = FacetedSearcher.getInstance();

Note<: When implementing Indexers it is highly recommended to extend thecom.liferay.portal.kernel.search.BaseIndexer class.

SearchEngineUtil

Internally each Indexer will make calls to the SearchEngineUtil which handles all the intricacies of the engine implementation. For the purpose of this document, we won't delve into the internals of SearchEngineUtil. But suffice it to say that all traffic to and from the search engine implementation passes through this class, and so when debuging problems it is often beneficial to enable debugging level logging on this class.

Performing the Search

Once an Indexer instance has been obtained, searches are performed by calling itssearch(SearchContext searchContext) method.

Hits & Documents

The result of the search method is an instance of the com.liferay.portal.kernel.search.Hits class.

Hits hits = indexer.search(searchContext);

This object contains any search results in the form of an array (or list) of com.liferay.portal.kernel.search.Document instances.

Document[] docs = hits.getDocs();

OR

List<Document> docs = hits.toList();

The results display typically involves iterating over this array. Each Document is effectively a hash map of the indexed fields and values.

Facet Rendering

Facet rendering is done by getting Facets from the SearchContext after the search has completed and passing each to a template as defined by the FacetConfiguration:

Map<String, Facet> facets = searchContext.getFacets();
List<Facet> facetsList = ListUtil.fromCollection(facets.values());
facetsList = ListUtil.sort(facetsList, new PropertyComparator("facetConfiguration.weight", false, false));for (Facet facet : facetsList) {if (facet.isStatic()) {continue;}FacetConfiguration facetConfiguration = facet.getFacetConfiguration();request.setAttribute("search.jsp-facet", facet);%><liferay-util:include page='<%= "/html/portlet/search/facets/" + facetConfiguration.getDisplayStyle() + ".jsp" %>' /><%
}

Facet Details (Terms and Frequencies)

A Facet's details are obtained by calling it's getFacetCollector() method which returns an instance ofcom.liferay.portal.kernel.search.facet.collector.FacetCollector class.

FacetCollector facetCollector = facet.getFacetCollector();

The primary responsibility of this class is to in turn provide access to TermCollector instances primarily by calling thegetTermCollectors() method, but also by getting a TermCollector by term value using thegetTermCollector(String term) method. There will be a TermCollector for each term that matches the search criteria, as well as the facet configuration.

List<TermCollector> termCollectors = facetCollector.getTermCollectors();

OR

TermCollectorterm termCollector = facetCollector.getTermCollector(term);

And finally, the com.liferay.portal.kernel.search.facet.collector.TermCollector class provides thegetFrequency() method.

<%= termCollector.getTerm() %> <span class="frequency">(<%= termCollector.getFrequency() %>)</span>

Rendered facet views (i.e. non-static facets) should result in UI code which allows dynamically passing facet parameters the interpretation by the implementation (see Facets as Filters). There are a number of examples in the/html/portlet/search/facets folder of the Search Portlet.

Liferay:Faceted Search in Liferay 6.1相关推荐

  1. python 读grid 数据_科学网—Python_机器学习_总结14:Grid search - 李军的博文

    机器学习中存在两类参数:通过训练数据学习得到的参数:---可认为是辨识得到的参数,例如模型系数: 在学习算法中单独需要优化的参数--超参.调优参数:---算法自身的系数,例如决策树的深度参数: Gri ...

  2. Liferay:RSS Portlet 不能配置的问题解决办法

    昨天碰到个问题,在页面上加了个RSS的portlet,想把默认的rss订阅地址改掉,可是点击小扳手,就是没有弹出设置菜单,本以为是浏览器的问题,但是换了几个浏览器也是一样. 看到浏览器中报js错误,如 ...

  3. Liferay 用PortletSession 实现不同Liferay之间通讯

    第一步: 写好PortletSession A 1.1  这是PortletSession A 的jsp页面代码 <%@ taglib uri="http://java.sun.com ...

  4. 一步一步SharePoint 2007之四十一:实现Search(4)——设定爬网Schedule

    下面将记录每一步的操作过程. 1.首先进入Document Center中的Documents列表页面,并上传一个名为"[url]www.eallies.com.doc[/url]" ...

  5. vue_music:搜索search.vue

    1. 经典搜索框search-box.vue 通用组件的设计原则:解耦 1. 通过props,传递placeholder信息 props: {placeholder: {type: String,de ...

  6. 正则系列2: re.search用法

    re.search re.search扫描整个字符串并返回第一个成功的匹配. 该方法有3个参数,第一个就是你写的正则表达式,第二个匹配的目标字符串,第三个是一个匹配模式 re.search(patte ...

  7. PDF文档搜索工具:PDF Search Mac版

    PDF Search Mac版是一款运行在Mac平台上的PDF文档搜索工具,PDF Search for mac可以帮助用户快速搜索PDF文档,以便用户在数千个PDF文档之间即时查找最相关的页面,另外 ...

  8. ElasticSearch 学习笔记:Multi Search

    本文目录 1 简介 2 格式 3 header格式 4 body格式 5 返回格式 6 性能 7 相关文章 1 简介 批量查询接口(Multi Search API)允许在一次请求中执行多个查询操作, ...

  9. 数据结构:查找(Search)【详解】

    友情链接:数据结构专栏 目录 查找 [知识框架] 查找概论 一.查找的基本概念 顺序表查找 一.定义 二.算法 有序表查找 一.折半查找 二.插值查找 三.斐波那契查找 线性索引查找 一.稠密索引 二 ...

最新文章

  1. 听声辨位过时了!这个AI系统仅凭光回声就能得到3D图像
  2. 北斗导航 | C语言实现PPP(精密单点定位)
  3. 6条 Tips 为你照亮 GitHub 寻宝之路
  4. EventStore文件存储设计
  5. JavaFX UI控件教程(二十)之HTML Editor
  6. 数据链路层中的LLC
  7. Android开发中的logcat工具使用方法
  8. 制作centos的启动盘
  9. 快速崛起的物联网世界安全问题
  10. golang interface 类型转换_Golang面试题41道
  11. python笔记小白入门_python小白入门基础(七:集合与字典)
  12. 剑指 offer set 8 树的子结构
  13. 免费在线打字练习网站
  14. 小程序云开发实战一:小程序扫一扫获取到图书ISBN码(图书条形码)
  15. 4款微信公众号编辑器,哪个最好用?
  16. android6自定义锁屏,Android
  17. 问题 B: 结构体---职工信息结构体
  18. 【解题报告】2021牛客寒假算法基础集训营4
  19. 小米9私密相册怎么找_小米手机私密相册怎么用?怎么打开查看?
  20. 硕士毕业论文讨论部分怎么写啊?

热门文章

  1. 九联UNT403G/UNT413G_国科GK6323芯片_5621ds无线wifi_免拆卡刷固件
  2. 个人博客主页搭建随笔
  3. MIC:最大信息系数
  4. trunk+vtp+链路冗余 理解
  5. 美团脱颖而出的经验_使用条件格式使重要的Outlook邮件脱颖而出
  6. 第25届ccf-csp认证赛后
  7. 100集华为HCIE安全培训视频教材整理 | Agile Controller终端安全管理特性(六)
  8. 自然语言处理(七):AG_NEWS新闻分类任务(TORCHTEXT)
  9. java中io流,Reader和Writer,InputStream和OutputStream,转换流 InputStreamReader 和 OutputStreamWriter
  10. (进制转换)—— 十六进制转换